pi-nvidia-nim 1.1.22 → 1.1.23
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/README.md +17 -12
- package/index.ts +70 -91
- package/package.json +8 -4
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# pi-nvidia-nim
|
|
2
2
|
|
|
3
|
-
NVIDIA NIM API provider extension for [pi coding agent](https://github.com/earendil-works/pi-mono) - access 100+ models from [build.nvidia.com](https://build.nvidia.com) including DeepSeek V4 Flash/Pro, DeepSeek V3.2, Kimi K2.6,
|
|
3
|
+
NVIDIA NIM API provider extension for [pi coding agent](https://github.com/earendil-works/pi-mono) - access 100+ models from [build.nvidia.com](https://build.nvidia.com) including Inkling, MiniMax M3, DeepSeek V4 Flash/Pro, DeepSeek V3.2, Kimi K2.6, GLM-5, GLM-4.7, Qwen3, Llama 4, and many more.
|
|
4
4
|
|
|
5
5
|
https://github.com/user-attachments/assets/f44773e4-9bf8-4bb5-a9c0-d5938030701c
|
|
6
6
|
|
|
@@ -74,35 +74,40 @@ NVIDIA NIM models use a non-standard `chat_template_kwargs` parameter to enable
|
|
|
74
74
|
|
|
75
75
|
When you change the thinking level in pi (`Shift+Tab` to cycle), the extension:
|
|
76
76
|
|
|
77
|
-
1. **Maps thinking levels** to values each NIM model accepts.
|
|
77
|
+
1. **Maps thinking levels** to values each NIM model accepts. MiniMax M3 uses its native `disabled`/`adaptive`/`enabled` modes; Inkling and DeepSeek V4 map extended levels to `max`.
|
|
78
78
|
2. **Injects `chat_template_kwargs`** per model to actually enable thinking:
|
|
79
|
+
- Inkling: `{ reasoning_effort: "none" | "minimal" | "low" | "medium" | "high" | "max" }`
|
|
80
|
+
- MiniMax M3: `{ thinking_mode: "disabled" | "adaptive" | "enabled" }`
|
|
79
81
|
- DeepSeek V4: `{ thinking: true, reasoning_effort: "high" | "max" }`
|
|
80
82
|
- DeepSeek V3.x, R1 distills: `{ thinking: true }`
|
|
81
83
|
- GLM-5, GLM-4.7: `{ enable_thinking: true, clear_thinking: false }`
|
|
82
84
|
- Kimi K2.6, K2-thinking: `{ thinking: true }`
|
|
83
85
|
- Qwen3, QwQ: `{ enable_thinking: true }`
|
|
84
|
-
3. **Explicitly
|
|
86
|
+
3. **Explicitly selects the lowest/off setting** when thinking is "off" for configurable models. MiniMax M3 uses `disabled`; Inkling uses `none` as a conditioning hint rather than a guarantee of zero reasoning tokens.
|
|
85
87
|
4. **Uses `system` role** instead of `developer` for all NIM models - the `developer` role combined with `chat_template_kwargs` causes 500 errors on NIM.
|
|
86
88
|
|
|
87
89
|
### Supported thinking levels
|
|
88
90
|
|
|
89
91
|
| pi Level | NIM Mapping | Effect |
|
|
90
92
|
|----------|-------------|--------|
|
|
91
|
-
| off |
|
|
92
|
-
| minimal |
|
|
93
|
-
| low | low, or high for DeepSeek V4 | Thinking enabled |
|
|
94
|
-
| medium | medium, or high for DeepSeek V4 | Thinking enabled |
|
|
95
|
-
| high | high | Thinking enabled |
|
|
96
|
-
| xhigh |
|
|
93
|
+
| off | MiniMax M3 `disabled`; Inkling `none`; explicit disable elsewhere | No/lowest reasoning effort |
|
|
94
|
+
| minimal | MiniMax M3 `adaptive`; Inkling `minimal`; low/high where required | Thinking enabled when useful |
|
|
95
|
+
| low | MiniMax M3 `adaptive`; low, or high for DeepSeek V4 | Thinking enabled when useful |
|
|
96
|
+
| medium | MiniMax M3 `adaptive`; medium, or high for DeepSeek V4 | Thinking enabled when useful |
|
|
97
|
+
| high | MiniMax M3 `enabled`; high elsewhere | Thinking enabled |
|
|
98
|
+
| xhigh | MiniMax M3 `enabled`; max for Inkling/DeepSeek V4 | Extended thinking |
|
|
99
|
+
| max | MiniMax M3 `enabled`; max for Inkling/DeepSeek V4 | Maximum supported thinking |
|
|
97
100
|
|
|
98
101
|
## Available Models
|
|
99
102
|
|
|
100
|
-
The extension ships with curated metadata for
|
|
103
|
+
The extension ships with curated metadata for 44 featured models. At startup, it also queries the NVIDIA NIM API to discover additional models automatically.
|
|
101
104
|
|
|
102
105
|
### Featured Models
|
|
103
106
|
|
|
104
107
|
| Model | Reasoning | Vision | Context |
|
|
105
108
|
|-------|-----------|--------|---------|
|
|
109
|
+
| `thinkingmachines/inkling` | ✅ | ✅ | 1M |
|
|
110
|
+
| `minimaxai/minimax-m3` | ✅ | ✅ | 1M |
|
|
106
111
|
| `deepseek-ai/deepseek-v4-flash` | ✅ | | 1M |
|
|
107
112
|
| `deepseek-ai/deepseek-v4-pro` | ✅ | | 1M |
|
|
108
113
|
| `deepseek-ai/deepseek-v3.2` | ✅ | | 128K |
|
|
@@ -138,7 +143,7 @@ This extension uses `pi.registerProvider()` to register NVIDIA NIM as a custom p
|
|
|
138
143
|
The custom streamer:
|
|
139
144
|
1. Intercepts the request payload via `onPayload` callback
|
|
140
145
|
2. Injects `chat_template_kwargs` for models that need it to enable thinking
|
|
141
|
-
3. Maps unsupported thinking levels to NIM-compatible values
|
|
146
|
+
3. Maps unsupported thinking levels to NIM-compatible values while preserving MiniMax M3's native modes and Inkling's native effort presets
|
|
142
147
|
4. Suppresses `reasoning_effort` for models that don't respond to it (e.g., DeepSeek without kwargs)
|
|
143
148
|
5. Uses the standard OpenAI SSE streaming format - pi already parses `reasoning_content` and `reasoning` fields from streaming deltas
|
|
144
149
|
|
|
@@ -153,7 +158,7 @@ The only configuration needed is either the `NVIDIA_NIM_API_KEY` or `NVIDIA_API_
|
|
|
153
158
|
- If a model isn't in the curated list, it gets a conservative 32K context window and 8K max output tokens
|
|
154
159
|
- The extension filters out embedding, reward, safety, and other non-chat models automatically
|
|
155
160
|
- Rate limits on free preview keys are relatively strict; you may encounter 429 errors during heavy usage
|
|
156
|
-
- MiniMax models use `<think>` tags inline in content
|
|
161
|
+
- MiniMax M3 streams thinking through `reasoning_content`; older MiniMax models may use `<think>` tags inline in content
|
|
157
162
|
|
|
158
163
|
## License
|
|
159
164
|
|
package/index.ts
CHANGED
|
@@ -34,17 +34,16 @@
|
|
|
34
34
|
* thinking settings.
|
|
35
35
|
*/
|
|
36
36
|
|
|
37
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
38
|
-
import { join } from "node:path";
|
|
39
37
|
import type {
|
|
40
38
|
Api,
|
|
41
39
|
AssistantMessageEventStream,
|
|
42
40
|
Context,
|
|
43
41
|
Model,
|
|
44
42
|
SimpleStreamOptions,
|
|
43
|
+
ThinkingLevelMap,
|
|
45
44
|
} from "@earendil-works/pi-ai";
|
|
46
|
-
import { streamSimpleOpenAICompletions } from "@earendil-works/pi-ai";
|
|
47
|
-
import {
|
|
45
|
+
import { streamSimpleOpenAICompletions } from "@earendil-works/pi-ai/compat";
|
|
46
|
+
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
48
47
|
|
|
49
48
|
// =============================================================================
|
|
50
49
|
// Constants
|
|
@@ -55,6 +54,8 @@ const NVIDIA_NIM_API_KEY_ENV = "NVIDIA_NIM_API_KEY";
|
|
|
55
54
|
const NVIDIA_API_KEY_ENV = "NVIDIA_API_KEY";
|
|
56
55
|
const NVIDIA_API_KEY_ENV_NAMES = [NVIDIA_NIM_API_KEY_ENV, NVIDIA_API_KEY_ENV] as const;
|
|
57
56
|
const PROVIDER_NAME = "nvidia-nim";
|
|
57
|
+
const INKLING_MODEL_ID = "thinkingmachines/inkling";
|
|
58
|
+
const MINIMAX_M3_MODEL_ID = "minimaxai/minimax-m3";
|
|
58
59
|
|
|
59
60
|
// =============================================================================
|
|
60
61
|
// Per-model thinking configuration
|
|
@@ -185,7 +186,11 @@ const THINKING_CONFIGS: Record<string, ThinkingConfig> = {
|
|
|
185
186
|
// Reasoning models and their capabilities
|
|
186
187
|
// =============================================================================
|
|
187
188
|
|
|
188
|
-
const REASONING_MODELS = new Set(
|
|
189
|
+
const REASONING_MODELS = new Set([
|
|
190
|
+
...Object.keys(THINKING_CONFIGS),
|
|
191
|
+
INKLING_MODEL_ID,
|
|
192
|
+
MINIMAX_M3_MODEL_ID,
|
|
193
|
+
]);
|
|
189
194
|
|
|
190
195
|
// Models known to support image/vision input
|
|
191
196
|
const VISION_MODELS = new Set([
|
|
@@ -197,6 +202,8 @@ const VISION_MODELS = new Set([
|
|
|
197
202
|
"nvidia/llama-3.1-nemotron-nano-vl-8b-v1",
|
|
198
203
|
"nvidia/nemotron-nano-12b-v2-vl",
|
|
199
204
|
"nvidia/cosmos-reason2-8b",
|
|
205
|
+
INKLING_MODEL_ID,
|
|
206
|
+
MINIMAX_M3_MODEL_ID,
|
|
200
207
|
]);
|
|
201
208
|
|
|
202
209
|
// Embedding / non-chat models to skip
|
|
@@ -269,6 +276,7 @@ const CONTEXT_WINDOWS: Record<string, number> = {
|
|
|
269
276
|
"minimaxai/minimax-m2": 1048576,
|
|
270
277
|
"minimaxai/minimax-m2.1": 1048576,
|
|
271
278
|
"minimaxai/minimax-m2.7": 204800,
|
|
279
|
+
[MINIMAX_M3_MODEL_ID]: 1_048_576,
|
|
272
280
|
// Meta Llama
|
|
273
281
|
"meta/llama-3.1-405b-instruct": 131072,
|
|
274
282
|
"meta/llama-3.1-70b-instruct": 131072,
|
|
@@ -339,6 +347,8 @@ const CONTEXT_WINDOWS: Record<string, number> = {
|
|
|
339
347
|
"nvidia/llama-3.3-nemotron-super-49b-v1.5": 131072,
|
|
340
348
|
"nvidia/nemotron-4-340b-instruct": 4096,
|
|
341
349
|
"nvidia/nvidia-nemotron-nano-9b-v2": 131072,
|
|
350
|
+
// Thinking Machines
|
|
351
|
+
[INKLING_MODEL_ID]: 1_048_576,
|
|
342
352
|
// OpenAI open-source
|
|
343
353
|
"openai/gpt-oss-120b": 131072,
|
|
344
354
|
"openai/gpt-oss-20b": 131072,
|
|
@@ -396,6 +406,7 @@ const MAX_TOKENS: Record<string, number> = {
|
|
|
396
406
|
"minimaxai/minimax-m2": 8192,
|
|
397
407
|
"minimaxai/minimax-m2.1": 8192,
|
|
398
408
|
"minimaxai/minimax-m2.7": 8192,
|
|
409
|
+
[MINIMAX_M3_MODEL_ID]: 16_384,
|
|
399
410
|
"meta/llama-4-maverick-17b-128e-instruct": 16384,
|
|
400
411
|
"meta/llama-4-scout-17b-16e-instruct": 16384,
|
|
401
412
|
"z-ai/glm4.7": 16384,
|
|
@@ -406,6 +417,7 @@ const MAX_TOKENS: Record<string, number> = {
|
|
|
406
417
|
"openai/gpt-oss-20b": 16384,
|
|
407
418
|
"mistralai/mistral-large-3-675b-instruct-2512": 16384,
|
|
408
419
|
"mistralai/devstral-2-123b-instruct-2512": 32768,
|
|
420
|
+
[INKLING_MODEL_ID]: 16_384,
|
|
409
421
|
};
|
|
410
422
|
|
|
411
423
|
// =============================================================================
|
|
@@ -423,6 +435,7 @@ const FEATURED_MODELS = [
|
|
|
423
435
|
"moonshotai/kimi-k2-thinking",
|
|
424
436
|
"moonshotai/kimi-k2-instruct",
|
|
425
437
|
"moonshotai/kimi-k2-instruct-0905",
|
|
438
|
+
MINIMAX_M3_MODEL_ID,
|
|
426
439
|
"minimaxai/minimax-m2.1",
|
|
427
440
|
"minimaxai/minimax-m2",
|
|
428
441
|
"minimaxai/minimax-m2.7",
|
|
@@ -432,6 +445,7 @@ const FEATURED_MODELS = [
|
|
|
432
445
|
"openai/gpt-oss-20b",
|
|
433
446
|
"stepfun-ai/step-3.5-flash",
|
|
434
447
|
"bytedance/seed-oss-36b-instruct",
|
|
448
|
+
INKLING_MODEL_ID,
|
|
435
449
|
// Qwen
|
|
436
450
|
"qwen/qwen3-coder-480b-a35b-instruct",
|
|
437
451
|
"qwen/qwen3-235b-a22b",
|
|
@@ -479,14 +493,6 @@ const FEATURED_MODELS = [
|
|
|
479
493
|
* 4. Uses onPayload callback to mutate request params before they're sent
|
|
480
494
|
*/
|
|
481
495
|
type NimApiKeyEnvName = (typeof NVIDIA_API_KEY_ENV_NAMES)[number];
|
|
482
|
-
type AuthStorageLike = {
|
|
483
|
-
get?: (provider: string) => unknown;
|
|
484
|
-
};
|
|
485
|
-
|
|
486
|
-
interface NimApiKeyCredential {
|
|
487
|
-
type: "api_key";
|
|
488
|
-
key: string;
|
|
489
|
-
}
|
|
490
496
|
|
|
491
497
|
function getNimApiKeyEnv(): NimApiKeyEnvName | undefined {
|
|
492
498
|
return NVIDIA_API_KEY_ENV_NAMES.find((envName) => !!process.env[envName]);
|
|
@@ -521,57 +527,6 @@ function resolveNimApiKeyEnvReference(value: string): string | undefined {
|
|
|
521
527
|
return envValue || undefined;
|
|
522
528
|
}
|
|
523
529
|
|
|
524
|
-
function isNimApiKeyEnvValue(value: string): boolean {
|
|
525
|
-
return NVIDIA_API_KEY_ENV_NAMES.some((envName) => process.env[envName]?.trim() === value);
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
function isNimApiKeyCredential(credential: unknown): credential is NimApiKeyCredential {
|
|
529
|
-
return (
|
|
530
|
-
typeof credential === "object" &&
|
|
531
|
-
credential !== null &&
|
|
532
|
-
(credential as { type?: unknown }).type === "api_key" &&
|
|
533
|
-
typeof (credential as { key?: unknown }).key === "string"
|
|
534
|
-
);
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
function readStoredNimApiKeyConfig(): string | undefined {
|
|
538
|
-
try {
|
|
539
|
-
const authPath = join(getAgentDir(), "auth.json");
|
|
540
|
-
if (!existsSync(authPath)) return undefined;
|
|
541
|
-
|
|
542
|
-
const data = JSON.parse(readFileSync(authPath, "utf-8")) as Record<string, unknown>;
|
|
543
|
-
const credential = data[PROVIDER_NAME];
|
|
544
|
-
return isNimApiKeyCredential(credential) ? credential.key : undefined;
|
|
545
|
-
} catch {
|
|
546
|
-
return undefined;
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
function getStoredNimApiKeyConfig(authStorage?: AuthStorageLike): string | undefined {
|
|
551
|
-
if (authStorage) {
|
|
552
|
-
try {
|
|
553
|
-
const credential = authStorage.get?.(PROVIDER_NAME);
|
|
554
|
-
return isNimApiKeyCredential(credential) ? credential.key : undefined;
|
|
555
|
-
} catch {
|
|
556
|
-
return undefined;
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
return readStoredNimApiKeyConfig();
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
function hasStoredNimCommandCredential(authStorage?: AuthStorageLike): boolean {
|
|
564
|
-
return getStoredNimApiKeyConfig(authStorage)?.startsWith("!") ?? false;
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
function getStoredResolvedNimApiKey(authStorage?: AuthStorageLike): string | undefined {
|
|
568
|
-
const configuredApiKey = getStoredNimApiKeyConfig(authStorage)?.trim();
|
|
569
|
-
if (!configuredApiKey || configuredApiKey.startsWith("!")) return undefined;
|
|
570
|
-
|
|
571
|
-
const envValue = process.env[configuredApiKey]?.trim();
|
|
572
|
-
return envValue || configuredApiKey;
|
|
573
|
-
}
|
|
574
|
-
|
|
575
530
|
function normalizeResolvedNimApiKey(apiKey: string | undefined): string | undefined {
|
|
576
531
|
if (apiKey === undefined) return undefined;
|
|
577
532
|
|
|
@@ -583,23 +538,17 @@ function normalizeResolvedNimApiKey(apiKey: string | undefined): string | undefi
|
|
|
583
538
|
return trimmed;
|
|
584
539
|
}
|
|
585
540
|
|
|
586
|
-
function resolveNimApiKey(apiKey: string | undefined
|
|
541
|
+
function resolveNimApiKey(apiKey: string | undefined): string | undefined {
|
|
587
542
|
const resolvedApiKey = normalizeResolvedNimApiKey(apiKey);
|
|
588
|
-
const hasStoredCommandCredential = hasStoredNimCommandCredential(authStorage);
|
|
589
|
-
|
|
590
|
-
if (
|
|
591
|
-
hasStoredCommandCredential &&
|
|
592
|
-
(!resolvedApiKey || isNimApiKeyEnvPlaceholder(resolvedApiKey) || isNimApiKeyEnvValue(resolvedApiKey))
|
|
593
|
-
) {
|
|
594
|
-
throw new Error("NVIDIA NIM API key command resolved to an empty value.");
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
const storedApiKey = getStoredResolvedNimApiKey(authStorage);
|
|
598
|
-
if (storedApiKey && (!resolvedApiKey || isNimApiKeyEnvPlaceholder(resolvedApiKey))) return storedApiKey;
|
|
599
543
|
|
|
600
544
|
if (resolvedApiKey) {
|
|
601
545
|
const envReferenceApiKey = resolveNimApiKeyEnvReference(resolvedApiKey);
|
|
602
546
|
if (envReferenceApiKey) return envReferenceApiKey;
|
|
547
|
+
|
|
548
|
+
if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(resolvedApiKey) && Object.hasOwn(process.env, resolvedApiKey)) {
|
|
549
|
+
return normalizeResolvedNimApiKey(process.env[resolvedApiKey]);
|
|
550
|
+
}
|
|
551
|
+
|
|
603
552
|
if (!isNimApiKeyEnvPlaceholder(resolvedApiKey)) return resolvedApiKey;
|
|
604
553
|
}
|
|
605
554
|
|
|
@@ -642,7 +591,7 @@ function buildNimRequestHeaders(headers: SimpleStreamOptions["headers"], apiKey:
|
|
|
642
591
|
const resolvedHeaders: Record<string, string> = {};
|
|
643
592
|
|
|
644
593
|
for (const [key, value] of Object.entries(headers ?? {})) {
|
|
645
|
-
if (key.toLowerCase() === "authorization") continue;
|
|
594
|
+
if (key.toLowerCase() === "authorization" || value === null) continue;
|
|
646
595
|
resolvedHeaders[key] = value;
|
|
647
596
|
}
|
|
648
597
|
|
|
@@ -669,9 +618,9 @@ function nimStreamSimple(
|
|
|
669
618
|
const reasoning = options?.reasoning;
|
|
670
619
|
const isThinkingEnabled = !!reasoning;
|
|
671
620
|
|
|
672
|
-
//
|
|
673
|
-
//
|
|
674
|
-
const mappedReasoning = mapNimTopLevelReasoning(reasoning);
|
|
621
|
+
// Custom NIM thinking configs use the provider-wide effort mapping. Models that
|
|
622
|
+
// declare native chat-template compatibility keep their own named levels.
|
|
623
|
+
const mappedReasoning = thinkingConfig ? mapNimTopLevelReasoning(reasoning) : reasoning;
|
|
675
624
|
|
|
676
625
|
// For models that have a thinking config: we handle thinking via chat_template_kwargs.
|
|
677
626
|
// Suppress reasoning_effort (set reasoning to undefined) unless the model explicitly
|
|
@@ -743,6 +692,7 @@ interface NimModelEntry {
|
|
|
743
692
|
id: string;
|
|
744
693
|
name: string;
|
|
745
694
|
reasoning: boolean;
|
|
695
|
+
thinkingLevelMap?: ThinkingLevelMap;
|
|
746
696
|
input: ("text" | "image")[];
|
|
747
697
|
contextWindow: number;
|
|
748
698
|
maxTokens: number;
|
|
@@ -788,6 +738,35 @@ function buildModelEntry(modelId: string): NimModelEntry | null {
|
|
|
788
738
|
maxTokensField: "max_tokens",
|
|
789
739
|
};
|
|
790
740
|
|
|
741
|
+
// Inkling conditions reasoning through its chat template rather than a top-level
|
|
742
|
+
// reasoning_effort field. NVIDIA NIM accepts the same named effort presets as
|
|
743
|
+
// Inkling's tokenizer; map pi's extended levels to Inkling's 0.99 preset.
|
|
744
|
+
if (modelId === INKLING_MODEL_ID) {
|
|
745
|
+
entry.thinkingLevelMap = { off: "none", xhigh: "max", max: "max" };
|
|
746
|
+
entry.compat.thinkingFormat = "chat-template";
|
|
747
|
+
entry.compat.chatTemplateKwargs = {
|
|
748
|
+
reasoning_effort: { $var: "thinking.effort" },
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// MiniMax M3 exposes discrete disabled/adaptive/enabled reasoning modes through
|
|
753
|
+
// chat_template_kwargs.thinking_mode. Map pi's effort scale to the closest mode.
|
|
754
|
+
if (modelId === MINIMAX_M3_MODEL_ID) {
|
|
755
|
+
entry.thinkingLevelMap = {
|
|
756
|
+
off: "disabled",
|
|
757
|
+
minimal: "adaptive",
|
|
758
|
+
low: "adaptive",
|
|
759
|
+
medium: "adaptive",
|
|
760
|
+
high: "enabled",
|
|
761
|
+
xhigh: "enabled",
|
|
762
|
+
max: "enabled",
|
|
763
|
+
};
|
|
764
|
+
entry.compat.thinkingFormat = "chat-template";
|
|
765
|
+
entry.compat.chatTemplateKwargs = {
|
|
766
|
+
thinking_mode: { $var: "thinking.effort" },
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
|
|
791
770
|
// Mistral models on NIM need extra compat flags
|
|
792
771
|
if (modelId.startsWith("mistralai/")) {
|
|
793
772
|
entry.compat.requiresToolResultName = true;
|
|
@@ -819,14 +798,17 @@ function sanitizeNimLogMessage(message: string): string {
|
|
|
819
798
|
return message.replace(/nvapi-[A-Za-z0-9._-]+/g, "nvapi-[REDACTED]");
|
|
820
799
|
}
|
|
821
800
|
|
|
822
|
-
function notifyNimDiscoveryCredentialWarning(ctx:
|
|
823
|
-
ctx
|
|
801
|
+
function notifyNimDiscoveryCredentialWarning(ctx: ExtensionContext): void {
|
|
802
|
+
ctx.ui.notify(NIM_DISCOVERY_CREDENTIAL_WARNING, "warning");
|
|
824
803
|
}
|
|
825
804
|
|
|
826
|
-
async function resolveNimDiscoveryApiKey(ctx:
|
|
805
|
+
async function resolveNimDiscoveryApiKey(ctx: ExtensionContext): Promise<string | undefined> {
|
|
827
806
|
try {
|
|
828
|
-
const apiKey = await ctx
|
|
829
|
-
|
|
807
|
+
const apiKey = await ctx.modelRegistry.getApiKeyForProvider(PROVIDER_NAME);
|
|
808
|
+
if (apiKey === undefined && ctx.modelRegistry.getProviderAuthStatus(PROVIDER_NAME).configured) {
|
|
809
|
+
throw new Error("NVIDIA NIM configured credential resolved to an empty value.");
|
|
810
|
+
}
|
|
811
|
+
return resolveNimApiKey(apiKey);
|
|
830
812
|
} catch (error) {
|
|
831
813
|
const message = error instanceof Error ? error.message : String(error);
|
|
832
814
|
console.warn(`pi-nvidia-nim: ${sanitizeNimLogMessage(message)}`);
|
|
@@ -901,7 +883,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
901
883
|
});
|
|
902
884
|
|
|
903
885
|
// On session start, discover additional models from the API
|
|
904
|
-
pi.on("session_start", async (_event
|
|
886
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
905
887
|
const apiKey = await resolveNimDiscoveryApiKey(ctx);
|
|
906
888
|
if (!apiKey) return;
|
|
907
889
|
|
|
@@ -927,13 +909,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
927
909
|
}
|
|
928
910
|
}
|
|
929
911
|
|
|
930
|
-
//
|
|
931
|
-
// NOTE: must use ctx.modelRegistry.registerProvider() here, not pi.registerProvider().
|
|
932
|
-
// pi.registerProvider() only queues registrations for the initial extension load.
|
|
933
|
-
// From event handlers/commands, we need to call the registry directly.
|
|
912
|
+
// Runtime provider registrations now apply immediately through the extension API.
|
|
934
913
|
if (newModelsAdded > 0) {
|
|
935
914
|
const allModels = Array.from(modelMap.values());
|
|
936
|
-
|
|
915
|
+
pi.registerProvider(PROVIDER_NAME, {
|
|
937
916
|
baseUrl: NVIDIA_NIM_BASE_URL,
|
|
938
917
|
apiKey: getNimProviderApiKeyConfig(),
|
|
939
918
|
api: "openai-completions",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-nvidia-nim",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.23",
|
|
4
4
|
"description": "NVIDIA NIM API provider extension for pi coding agent — access 100+ models from build.nvidia.com",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -23,11 +23,15 @@
|
|
|
23
23
|
"test": "node --test test/*.test.mjs"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@earendil-works/pi-ai": "^0.
|
|
27
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
28
|
-
"@types/node": "^
|
|
26
|
+
"@earendil-works/pi-ai": "^0.80.10",
|
|
27
|
+
"@earendil-works/pi-coding-agent": "^0.80.10",
|
|
28
|
+
"@types/node": "^24.0.0",
|
|
29
29
|
"typescript": "^6.0.3"
|
|
30
30
|
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"@earendil-works/pi-ai": "*",
|
|
33
|
+
"@earendil-works/pi-coding-agent": "*"
|
|
34
|
+
},
|
|
31
35
|
"repository": {
|
|
32
36
|
"type": "git",
|
|
33
37
|
"url": "https://github.com/xRyul/pi-nvidia-nim.git"
|