@juspay/neurolink 9.59.6 → 9.60.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/CHANGELOG.md +12 -0
- package/README.md +11 -7
- package/dist/adapters/providerImageAdapter.js +52 -2
- package/dist/browser/neurolink.min.js +352 -352
- package/dist/cli/commands/proxy.js +54 -11
- package/dist/cli/factories/commandFactory.js +15 -1
- package/dist/cli/utils/interactiveSetup.js +64 -0
- package/dist/constants/contextWindows.d.ts +5 -1
- package/dist/constants/contextWindows.js +67 -3
- package/dist/constants/enums.d.ts +52 -0
- package/dist/constants/enums.js +63 -0
- package/dist/core/baseProvider.d.ts +15 -6
- package/dist/core/baseProvider.js +28 -0
- package/dist/factories/providerRegistry.js +25 -1
- package/dist/lib/adapters/providerImageAdapter.js +52 -2
- package/dist/lib/constants/contextWindows.d.ts +5 -1
- package/dist/lib/constants/contextWindows.js +67 -3
- package/dist/lib/constants/enums.d.ts +52 -0
- package/dist/lib/constants/enums.js +63 -0
- package/dist/lib/core/baseProvider.d.ts +15 -6
- package/dist/lib/core/baseProvider.js +28 -0
- package/dist/lib/factories/providerRegistry.js +25 -1
- package/dist/lib/providers/deepseek.d.ts +29 -0
- package/dist/lib/providers/deepseek.js +216 -0
- package/dist/lib/providers/index.d.ts +4 -0
- package/dist/lib/providers/index.js +4 -0
- package/dist/lib/providers/llamaCpp.d.ts +34 -0
- package/dist/lib/providers/llamaCpp.js +315 -0
- package/dist/lib/providers/lmStudio.d.ts +34 -0
- package/dist/lib/providers/lmStudio.js +306 -0
- package/dist/lib/providers/nvidiaNim.d.ts +31 -0
- package/dist/lib/providers/nvidiaNim.js +354 -0
- package/dist/lib/proxy/proxyFetch.d.ts +9 -0
- package/dist/lib/proxy/proxyFetch.js +6 -1
- package/dist/lib/types/providers.d.ts +37 -2
- package/dist/lib/types/providers.js +1 -1
- package/dist/lib/utils/modelChoices.js +68 -4
- package/dist/lib/utils/pricing.d.ts +5 -0
- package/dist/lib/utils/pricing.js +94 -3
- package/dist/lib/utils/providerConfig.d.ts +16 -0
- package/dist/lib/utils/providerConfig.js +82 -0
- package/dist/providers/deepseek.d.ts +29 -0
- package/dist/providers/deepseek.js +215 -0
- package/dist/providers/index.d.ts +4 -0
- package/dist/providers/index.js +4 -0
- package/dist/providers/llamaCpp.d.ts +34 -0
- package/dist/providers/llamaCpp.js +314 -0
- package/dist/providers/lmStudio.d.ts +34 -0
- package/dist/providers/lmStudio.js +305 -0
- package/dist/providers/nvidiaNim.d.ts +31 -0
- package/dist/providers/nvidiaNim.js +353 -0
- package/dist/proxy/proxyFetch.d.ts +9 -0
- package/dist/proxy/proxyFetch.js +6 -1
- package/dist/types/providers.d.ts +37 -2
- package/dist/utils/modelChoices.js +68 -4
- package/dist/utils/pricing.d.ts +5 -0
- package/dist/utils/pricing.js +94 -3
- package/dist/utils/providerConfig.d.ts +16 -0
- package/dist/utils/providerConfig.js +82 -0
- package/package.json +19 -12
|
@@ -224,6 +224,67 @@ const PRICING = {
|
|
|
224
224
|
output: 0.15 / 1_000_000,
|
|
225
225
|
},
|
|
226
226
|
},
|
|
227
|
+
deepseek: {
|
|
228
|
+
"deepseek-chat": {
|
|
229
|
+
input: 0.27 / 1_000_000,
|
|
230
|
+
output: 1.1 / 1_000_000,
|
|
231
|
+
cacheRead: 0.07 / 1_000_000,
|
|
232
|
+
},
|
|
233
|
+
"deepseek-reasoner": {
|
|
234
|
+
input: 0.55 / 1_000_000,
|
|
235
|
+
output: 2.19 / 1_000_000,
|
|
236
|
+
cacheRead: 0.14 / 1_000_000,
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
"nvidia-nim": {
|
|
240
|
+
"meta/llama-3.3-70b-instruct": {
|
|
241
|
+
input: 0.4 / 1_000_000,
|
|
242
|
+
output: 0.4 / 1_000_000,
|
|
243
|
+
},
|
|
244
|
+
"meta/llama-3.1-405b-instruct": {
|
|
245
|
+
input: 1.79 / 1_000_000,
|
|
246
|
+
output: 1.79 / 1_000_000,
|
|
247
|
+
},
|
|
248
|
+
"meta/llama-3.1-70b-instruct": {
|
|
249
|
+
input: 0.4 / 1_000_000,
|
|
250
|
+
output: 0.4 / 1_000_000,
|
|
251
|
+
},
|
|
252
|
+
"meta/llama-3.2-90b-vision-instruct": {
|
|
253
|
+
input: 0.5 / 1_000_000,
|
|
254
|
+
output: 0.5 / 1_000_000,
|
|
255
|
+
},
|
|
256
|
+
"nvidia/llama-3.3-nemotron-super-49b-v1": {
|
|
257
|
+
input: 0.3 / 1_000_000,
|
|
258
|
+
output: 0.3 / 1_000_000,
|
|
259
|
+
},
|
|
260
|
+
"deepseek-ai/deepseek-r1": {
|
|
261
|
+
input: 0.55 / 1_000_000,
|
|
262
|
+
output: 2.19 / 1_000_000,
|
|
263
|
+
},
|
|
264
|
+
"mistralai/mixtral-8x22b-instruct-v0.1": {
|
|
265
|
+
input: 0.6 / 1_000_000,
|
|
266
|
+
output: 0.6 / 1_000_000,
|
|
267
|
+
},
|
|
268
|
+
"mistralai/mixtral-8x7b-instruct-v0.1": {
|
|
269
|
+
input: 0.24 / 1_000_000,
|
|
270
|
+
output: 0.24 / 1_000_000,
|
|
271
|
+
},
|
|
272
|
+
"microsoft/phi-4": { input: 0.07 / 1_000_000, output: 0.07 / 1_000_000 },
|
|
273
|
+
"google/gemma-3-27b-it": {
|
|
274
|
+
input: 0.07 / 1_000_000,
|
|
275
|
+
output: 0.07 / 1_000_000,
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
"lm-studio": {
|
|
279
|
+
// Local inference — there is no upstream USD price. Reporting a fabricated
|
|
280
|
+
// symbolic rate here misstated spend in analytics/spans, so the rate is
|
|
281
|
+
// explicitly zero. `calculateCost()` returns 0 for zero rates and the CLI
|
|
282
|
+
// / span renderers already treat 0 as "no billable cost" (no $ shown).
|
|
283
|
+
_default: { input: 0, output: 0 },
|
|
284
|
+
},
|
|
285
|
+
llamacpp: {
|
|
286
|
+
_default: { input: 0, output: 0 },
|
|
287
|
+
},
|
|
227
288
|
};
|
|
228
289
|
/**
|
|
229
290
|
* Map of normalized provider aliases to canonical PRICING keys.
|
|
@@ -246,6 +307,12 @@ const PROVIDER_ALIASES = {
|
|
|
246
307
|
litellm: "__cross_provider__",
|
|
247
308
|
openrouter: "__cross_provider__",
|
|
248
309
|
openaicompatible: "__cross_provider__",
|
|
310
|
+
deepseek: "deepseek",
|
|
311
|
+
nvidianim: "nvidia-nim",
|
|
312
|
+
nim: "nvidia-nim",
|
|
313
|
+
nvidia: "nvidia-nim",
|
|
314
|
+
lmstudio: "lm-studio",
|
|
315
|
+
llamacpp: "llamacpp",
|
|
249
316
|
};
|
|
250
317
|
/**
|
|
251
318
|
* Look up per-token rates for a provider/model combination.
|
|
@@ -287,14 +354,19 @@ function findRates(provider, model) {
|
|
|
287
354
|
if (providerPricing[model]) {
|
|
288
355
|
return providerPricing[model];
|
|
289
356
|
}
|
|
290
|
-
// Longest-prefix match
|
|
291
|
-
const sortedKeys = Object.keys(providerPricing)
|
|
357
|
+
// Longest-prefix match (skip the synthetic "_default" sentinel below)
|
|
358
|
+
const sortedKeys = Object.keys(providerPricing)
|
|
359
|
+
.filter((k) => k !== "_default")
|
|
360
|
+
.sort((a, b) => b.length - a.length);
|
|
292
361
|
const key = sortedKeys.find((k) => model.startsWith(k));
|
|
293
362
|
if (key) {
|
|
294
363
|
return providerPricing[key];
|
|
295
364
|
}
|
|
296
365
|
// Fallback: Vertex hosts both Claude and Gemini models.
|
|
297
366
|
// If no match found under "vertex", try "google" pricing for Gemini models.
|
|
367
|
+
// (Run BEFORE the provider-level _default fallback so that Vertex Gemini
|
|
368
|
+
// requests get the more specific Google rates rather than a generic Vertex
|
|
369
|
+
// _default if one is ever added.)
|
|
298
370
|
if (normalizedProvider === "vertex" && model.startsWith("gemini")) {
|
|
299
371
|
const googlePricing = PRICING["google"];
|
|
300
372
|
if (googlePricing) {
|
|
@@ -308,6 +380,13 @@ function findRates(provider, model) {
|
|
|
308
380
|
}
|
|
309
381
|
}
|
|
310
382
|
}
|
|
383
|
+
// Provider-level fallback: when a pricing table only has _default (or has
|
|
384
|
+
// no entry matching the specific model), use _default. This is mainly for
|
|
385
|
+
// local/symbolic providers (lm-studio, llamacpp) that don't enumerate per-
|
|
386
|
+
// model pricing.
|
|
387
|
+
if (providerPricing["_default"]) {
|
|
388
|
+
return providerPricing["_default"];
|
|
389
|
+
}
|
|
311
390
|
return undefined;
|
|
312
391
|
}
|
|
313
392
|
/**
|
|
@@ -334,8 +413,20 @@ export function calculateCost(provider, model, usage) {
|
|
|
334
413
|
* Check if pricing is available for a provider/model combination.
|
|
335
414
|
* Checks the rate table directly instead of computing a cost,
|
|
336
415
|
* so even very cheap models (e.g. gemini-1.5-flash) are detected correctly.
|
|
416
|
+
*
|
|
417
|
+
* Zero-rate entries (the local-provider `_default` for lm-studio / llamacpp)
|
|
418
|
+
* count as "no pricing" — those providers explicitly don't have an upstream
|
|
419
|
+
* USD price, and any caller gated by `hasPricing()` should treat them as
|
|
420
|
+
* non-billable rather than zero-cost-billable.
|
|
337
421
|
*/
|
|
338
422
|
export function hasPricing(provider, model) {
|
|
339
|
-
|
|
423
|
+
const rates = findRates(provider, model);
|
|
424
|
+
if (!rates) {
|
|
425
|
+
return false;
|
|
426
|
+
}
|
|
427
|
+
return (rates.input > 0 ||
|
|
428
|
+
rates.output > 0 ||
|
|
429
|
+
(rates.cacheRead ?? 0) > 0 ||
|
|
430
|
+
(rates.cacheCreation ?? 0) > 0);
|
|
340
431
|
}
|
|
341
432
|
//# sourceMappingURL=pricing.js.map
|
|
@@ -107,6 +107,22 @@ export declare function createAzureEndpointConfig(): ProviderConfigOptions;
|
|
|
107
107
|
* Creates OpenAI Compatible provider configuration
|
|
108
108
|
*/
|
|
109
109
|
export declare function createOpenAICompatibleConfig(): ProviderConfigOptions;
|
|
110
|
+
/**
|
|
111
|
+
* Creates DeepSeek provider configuration
|
|
112
|
+
*/
|
|
113
|
+
export declare function createDeepSeekConfig(): ProviderConfigOptions;
|
|
114
|
+
/**
|
|
115
|
+
* Creates NVIDIA NIM provider configuration
|
|
116
|
+
*/
|
|
117
|
+
export declare function createNvidiaNimConfig(): ProviderConfigOptions;
|
|
118
|
+
/**
|
|
119
|
+
* Creates LM Studio provider configuration (local server)
|
|
120
|
+
*/
|
|
121
|
+
export declare function createLmStudioConfig(): ProviderConfigOptions;
|
|
122
|
+
/**
|
|
123
|
+
* Creates llama.cpp provider configuration (local server)
|
|
124
|
+
*/
|
|
125
|
+
export declare function createLlamaCppConfig(): ProviderConfigOptions;
|
|
110
126
|
/**
|
|
111
127
|
* Creates Google Vertex Project ID configuration
|
|
112
128
|
*/
|
|
@@ -85,6 +85,10 @@ export function validateApiKeyEnhanced(config, enableFormatValidation = false) {
|
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
if (!apiKey) {
|
|
88
|
+
if (config.optional) {
|
|
89
|
+
// Local providers — base URL defaulted; treat as valid with empty value.
|
|
90
|
+
return { isValid: true, apiKey: "" };
|
|
91
|
+
}
|
|
88
92
|
return {
|
|
89
93
|
isValid: false,
|
|
90
94
|
apiKey: "",
|
|
@@ -131,6 +135,12 @@ export function validateApiKey(config) {
|
|
|
131
135
|
}
|
|
132
136
|
}
|
|
133
137
|
if (!apiKey) {
|
|
138
|
+
// Local providers (LM Studio, llama.cpp) treat envVarName as a base-URL
|
|
139
|
+
// override, not a credential. Returning "" lets callers fall back to the
|
|
140
|
+
// documented default URL without raising a configuration error.
|
|
141
|
+
if (config.optional) {
|
|
142
|
+
return "";
|
|
143
|
+
}
|
|
134
144
|
throw new Error(createConfigErrorMessage(config));
|
|
135
145
|
}
|
|
136
146
|
return apiKey;
|
|
@@ -366,6 +376,78 @@ export function createOpenAICompatibleConfig() {
|
|
|
366
376
|
],
|
|
367
377
|
};
|
|
368
378
|
}
|
|
379
|
+
/**
|
|
380
|
+
* Creates DeepSeek provider configuration
|
|
381
|
+
*/
|
|
382
|
+
export function createDeepSeekConfig() {
|
|
383
|
+
return {
|
|
384
|
+
providerName: "DeepSeek",
|
|
385
|
+
envVarName: "DEEPSEEK_API_KEY",
|
|
386
|
+
setupUrl: "https://platform.deepseek.com/api_keys",
|
|
387
|
+
description: "API key",
|
|
388
|
+
instructions: [
|
|
389
|
+
"1. Visit: https://platform.deepseek.com/api_keys",
|
|
390
|
+
"2. Create or sign in to your DeepSeek account",
|
|
391
|
+
"3. Generate a new API key",
|
|
392
|
+
"4. Set DEEPSEEK_API_KEY in your .env file",
|
|
393
|
+
],
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Creates NVIDIA NIM provider configuration
|
|
398
|
+
*/
|
|
399
|
+
export function createNvidiaNimConfig() {
|
|
400
|
+
return {
|
|
401
|
+
providerName: "NVIDIA NIM",
|
|
402
|
+
envVarName: "NVIDIA_NIM_API_KEY",
|
|
403
|
+
setupUrl: "https://build.nvidia.com/settings/api-keys",
|
|
404
|
+
description: "API key",
|
|
405
|
+
instructions: [
|
|
406
|
+
"1. Visit: https://build.nvidia.com/",
|
|
407
|
+
"2. Sign in with your NVIDIA developer account",
|
|
408
|
+
"3. Open Settings → API Keys",
|
|
409
|
+
"4. Generate a new API key (Bearer token)",
|
|
410
|
+
"5. Set NVIDIA_NIM_API_KEY in your .env file",
|
|
411
|
+
],
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Creates LM Studio provider configuration (local server)
|
|
416
|
+
*/
|
|
417
|
+
export function createLmStudioConfig() {
|
|
418
|
+
return {
|
|
419
|
+
providerName: "LM Studio",
|
|
420
|
+
envVarName: "LM_STUDIO_BASE_URL",
|
|
421
|
+
setupUrl: "https://lmstudio.ai/",
|
|
422
|
+
description: "LM Studio server URL",
|
|
423
|
+
instructions: [
|
|
424
|
+
"1. Install LM Studio: https://lmstudio.ai/",
|
|
425
|
+
"2. Open LM Studio and download a model (e.g. Llama 3.2 3B Instruct)",
|
|
426
|
+
'3. Click "Local Server" → Start Server',
|
|
427
|
+
"4. Default URL is http://localhost:1234/v1 (override via LM_STUDIO_BASE_URL)",
|
|
428
|
+
],
|
|
429
|
+
// Base URL is optional — defaults to http://localhost:1234/v1 if unset.
|
|
430
|
+
optional: true,
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Creates llama.cpp provider configuration (local server)
|
|
435
|
+
*/
|
|
436
|
+
export function createLlamaCppConfig() {
|
|
437
|
+
return {
|
|
438
|
+
providerName: "llama.cpp",
|
|
439
|
+
envVarName: "LLAMACPP_BASE_URL",
|
|
440
|
+
setupUrl: "https://github.com/ggerganov/llama.cpp",
|
|
441
|
+
description: "llama.cpp server URL",
|
|
442
|
+
instructions: [
|
|
443
|
+
"1. Build llama.cpp: https://github.com/ggerganov/llama.cpp#build",
|
|
444
|
+
"2. Run: ./llama-server -m model.gguf --port 8080",
|
|
445
|
+
"3. Default URL is http://localhost:8080/v1 (override via LLAMACPP_BASE_URL)",
|
|
446
|
+
],
|
|
447
|
+
// Base URL is optional — defaults to http://localhost:8080/v1 if unset.
|
|
448
|
+
optional: true,
|
|
449
|
+
};
|
|
450
|
+
}
|
|
369
451
|
/**
|
|
370
452
|
* Creates Google Vertex Project ID configuration
|
|
371
453
|
*/
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type LanguageModel } from "ai";
|
|
2
|
+
import type { AIProviderName } from "../constants/enums.js";
|
|
3
|
+
import { BaseProvider } from "../core/baseProvider.js";
|
|
4
|
+
import type { NeurolinkCredentials, StreamOptions, StreamResult, ValidationSchema } from "../types/index.js";
|
|
5
|
+
/**
|
|
6
|
+
* DeepSeek Provider
|
|
7
|
+
* OpenAI-compatible chat completions; supports deepseek-chat (V3) and
|
|
8
|
+
* deepseek-reasoner (R1, exposes reasoning_content).
|
|
9
|
+
*/
|
|
10
|
+
export declare class DeepSeekProvider extends BaseProvider {
|
|
11
|
+
private model;
|
|
12
|
+
private apiKey;
|
|
13
|
+
private baseURL;
|
|
14
|
+
constructor(modelName?: string, sdk?: unknown, _region?: string, credentials?: NeurolinkCredentials["deepseek"]);
|
|
15
|
+
protected executeStream(options: StreamOptions, _analysisSchema?: ValidationSchema): Promise<StreamResult>;
|
|
16
|
+
private executeStreamInner;
|
|
17
|
+
protected getProviderName(): AIProviderName;
|
|
18
|
+
protected getDefaultModel(): string;
|
|
19
|
+
protected getAISDKModel(): LanguageModel;
|
|
20
|
+
protected formatProviderError(error: unknown): Error;
|
|
21
|
+
validateConfiguration(): Promise<boolean>;
|
|
22
|
+
getConfiguration(): {
|
|
23
|
+
provider: AIProviderName;
|
|
24
|
+
model: string;
|
|
25
|
+
defaultModel: string;
|
|
26
|
+
baseURL: string;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export default DeepSeekProvider;
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { createOpenAI } from "@ai-sdk/openai";
|
|
2
|
+
import { stepCountIs, streamText } from "ai";
|
|
3
|
+
import { DeepSeekModels } from "../constants/enums.js";
|
|
4
|
+
import { BaseProvider } from "../core/baseProvider.js";
|
|
5
|
+
import { DEFAULT_MAX_STEPS } from "../core/constants.js";
|
|
6
|
+
import { streamAnalyticsCollector } from "../core/streamAnalytics.js";
|
|
7
|
+
import { createProxyFetch, maskProxyUrl } from "../proxy/proxyFetch.js";
|
|
8
|
+
import { tracers, ATTR, withClientSpan } from "../telemetry/index.js";
|
|
9
|
+
import { logger } from "../utils/logger.js";
|
|
10
|
+
import { createDeepSeekConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
|
|
11
|
+
import { composeAbortSignals, createTimeoutController, TimeoutError, } from "../utils/timeout.js";
|
|
12
|
+
import { emitToolEndFromStepFinish } from "../utils/toolEndEmitter.js";
|
|
13
|
+
import { resolveToolChoice } from "../utils/toolChoice.js";
|
|
14
|
+
import { toAnalyticsStreamResult } from "./providerTypeUtils.js";
|
|
15
|
+
const makeLoggingFetch = (provider) => {
|
|
16
|
+
const base = createProxyFetch();
|
|
17
|
+
return (async (input, init) => {
|
|
18
|
+
const url = typeof input === "string"
|
|
19
|
+
? input
|
|
20
|
+
: input instanceof URL
|
|
21
|
+
? input.toString()
|
|
22
|
+
: input.url;
|
|
23
|
+
const reqSize = init?.body && typeof init.body === "string" ? init.body.length : 0;
|
|
24
|
+
const response = await base(input, init);
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
// Don't fall back to the raw URL — that would defeat the redaction.
|
|
27
|
+
const safeUrl = maskProxyUrl(url) ?? "<redacted>";
|
|
28
|
+
if (process.env.NEUROLINK_DEBUG_HTTP === "1") {
|
|
29
|
+
const clone = response.clone();
|
|
30
|
+
const body = await clone.text().catch(() => "<unreadable>");
|
|
31
|
+
logger.warn(`[${provider}] upstream ${response.status}`, {
|
|
32
|
+
url: safeUrl,
|
|
33
|
+
body: body.slice(0, 800),
|
|
34
|
+
reqSize,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
logger.warn(`[${provider}] upstream ${response.status} url=${safeUrl} reqSize=${reqSize}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return response;
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
const DEEPSEEK_DEFAULT_BASE_URL = "https://api.deepseek.com";
|
|
45
|
+
const getDeepSeekApiKey = () => {
|
|
46
|
+
return validateApiKey(createDeepSeekConfig());
|
|
47
|
+
};
|
|
48
|
+
const getDefaultDeepSeekModel = () => {
|
|
49
|
+
return getProviderModel("DEEPSEEK_MODEL", DeepSeekModels.DEEPSEEK_CHAT);
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* DeepSeek Provider
|
|
53
|
+
* OpenAI-compatible chat completions; supports deepseek-chat (V3) and
|
|
54
|
+
* deepseek-reasoner (R1, exposes reasoning_content).
|
|
55
|
+
*/
|
|
56
|
+
export class DeepSeekProvider extends BaseProvider {
|
|
57
|
+
model;
|
|
58
|
+
apiKey;
|
|
59
|
+
baseURL;
|
|
60
|
+
constructor(modelName, sdk, _region, credentials) {
|
|
61
|
+
const validatedNeurolink = sdk && typeof sdk === "object" && "getInMemoryServers" in sdk
|
|
62
|
+
? sdk
|
|
63
|
+
: undefined;
|
|
64
|
+
super(modelName, "deepseek", validatedNeurolink);
|
|
65
|
+
// Trim the override before applying precedence. A blank/whitespace
|
|
66
|
+
// `credentials.apiKey` should NOT bypass `getDeepSeekApiKey()` — that
|
|
67
|
+
// would build a client with an unusable bearer token and fail at request
|
|
68
|
+
// time with a confusing 401 instead of at construction time.
|
|
69
|
+
const overrideApiKey = credentials?.apiKey?.trim();
|
|
70
|
+
this.apiKey =
|
|
71
|
+
overrideApiKey && overrideApiKey.length > 0
|
|
72
|
+
? overrideApiKey
|
|
73
|
+
: getDeepSeekApiKey();
|
|
74
|
+
this.baseURL =
|
|
75
|
+
credentials?.baseURL ??
|
|
76
|
+
process.env.DEEPSEEK_BASE_URL ??
|
|
77
|
+
DEEPSEEK_DEFAULT_BASE_URL;
|
|
78
|
+
const deepseek = createOpenAI({
|
|
79
|
+
apiKey: this.apiKey,
|
|
80
|
+
baseURL: this.baseURL,
|
|
81
|
+
fetch: makeLoggingFetch("deepseek"),
|
|
82
|
+
});
|
|
83
|
+
// .chat() returns a Chat Completions model. The default factory call
|
|
84
|
+
// returns a Responses API model which OpenAI-compat providers don't implement.
|
|
85
|
+
this.model = deepseek.chat(this.modelName);
|
|
86
|
+
logger.debug("DeepSeek Provider initialized", {
|
|
87
|
+
modelName: this.modelName,
|
|
88
|
+
providerName: this.providerName,
|
|
89
|
+
baseURL: this.baseURL,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
async executeStream(options, _analysisSchema) {
|
|
93
|
+
return withClientSpan({
|
|
94
|
+
name: "neurolink.provider.stream",
|
|
95
|
+
tracer: tracers.provider,
|
|
96
|
+
attributes: {
|
|
97
|
+
[ATTR.GEN_AI_SYSTEM]: "deepseek",
|
|
98
|
+
[ATTR.GEN_AI_MODEL]: this.modelName,
|
|
99
|
+
[ATTR.GEN_AI_OPERATION]: "stream",
|
|
100
|
+
[ATTR.NL_STREAM_MODE]: true,
|
|
101
|
+
},
|
|
102
|
+
}, async () => this.executeStreamInner(options));
|
|
103
|
+
}
|
|
104
|
+
async executeStreamInner(options) {
|
|
105
|
+
this.validateStreamOptions(options);
|
|
106
|
+
const startTime = Date.now();
|
|
107
|
+
const timeout = this.getTimeout(options);
|
|
108
|
+
const timeoutController = createTimeoutController(timeout, this.providerName, "stream");
|
|
109
|
+
try {
|
|
110
|
+
const shouldUseTools = !options.disableTools && this.supportsTools();
|
|
111
|
+
const tools = shouldUseTools
|
|
112
|
+
? options.tools || (await this.getAllTools())
|
|
113
|
+
: {};
|
|
114
|
+
const messages = await this.buildMessagesForStream(options);
|
|
115
|
+
const model = await this.getAISDKModelWithMiddleware(options);
|
|
116
|
+
const isReasoner = this.modelName === DeepSeekModels.DEEPSEEK_REASONER;
|
|
117
|
+
const result = await streamText({
|
|
118
|
+
model,
|
|
119
|
+
messages,
|
|
120
|
+
temperature: options.temperature,
|
|
121
|
+
maxOutputTokens: options.maxTokens,
|
|
122
|
+
tools,
|
|
123
|
+
stopWhen: stepCountIs(options.maxSteps || DEFAULT_MAX_STEPS),
|
|
124
|
+
toolChoice: resolveToolChoice(options, tools, shouldUseTools),
|
|
125
|
+
abortSignal: composeAbortSignals(options.abortSignal, timeoutController?.controller.signal),
|
|
126
|
+
// DeepSeek's `thinking` mode is opt-in for chat models — only enable
|
|
127
|
+
// when the caller explicitly asks for it via `thinkingConfig.enabled`.
|
|
128
|
+
// Forcing it on every chat call would trigger extended reasoning for
|
|
129
|
+
// simple prompts (and ignore reasoner models which control it natively).
|
|
130
|
+
providerOptions: !isReasoner && options.thinkingConfig?.enabled
|
|
131
|
+
? {
|
|
132
|
+
openai: {
|
|
133
|
+
thinking: { type: "enabled" },
|
|
134
|
+
},
|
|
135
|
+
}
|
|
136
|
+
: undefined,
|
|
137
|
+
experimental_telemetry: this.telemetryHandler.getTelemetryConfig(options),
|
|
138
|
+
experimental_repairToolCall: this.getToolCallRepairFn(options),
|
|
139
|
+
onStepFinish: ({ toolCalls, toolResults }) => {
|
|
140
|
+
emitToolEndFromStepFinish(this.neurolink?.getEventEmitter(), toolResults);
|
|
141
|
+
this.handleToolExecutionStorage(toolCalls, toolResults, options, new Date()).catch((error) => {
|
|
142
|
+
logger.warn("[DeepSeekProvider] Failed to store tool executions", {
|
|
143
|
+
provider: this.providerName,
|
|
144
|
+
error: error instanceof Error ? error.message : String(error),
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
timeoutController?.cleanup();
|
|
150
|
+
const transformedStream = this.createTextStream(result);
|
|
151
|
+
const analyticsPromise = streamAnalyticsCollector.createAnalytics(this.providerName, this.modelName, toAnalyticsStreamResult(result), Date.now() - startTime, {
|
|
152
|
+
requestId: `deepseek-stream-${Date.now()}`,
|
|
153
|
+
streamingMode: true,
|
|
154
|
+
});
|
|
155
|
+
return {
|
|
156
|
+
stream: transformedStream,
|
|
157
|
+
provider: this.providerName,
|
|
158
|
+
model: this.modelName,
|
|
159
|
+
analytics: analyticsPromise,
|
|
160
|
+
metadata: { startTime, streamId: `deepseek-${Date.now()}` },
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
timeoutController?.cleanup();
|
|
165
|
+
throw this.handleProviderError(error);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
getProviderName() {
|
|
169
|
+
return this.providerName;
|
|
170
|
+
}
|
|
171
|
+
getDefaultModel() {
|
|
172
|
+
return getDefaultDeepSeekModel();
|
|
173
|
+
}
|
|
174
|
+
getAISDKModel() {
|
|
175
|
+
return this.model;
|
|
176
|
+
}
|
|
177
|
+
formatProviderError(error) {
|
|
178
|
+
if (error instanceof TimeoutError) {
|
|
179
|
+
return new Error(`DeepSeek request timed out: ${error.message}`);
|
|
180
|
+
}
|
|
181
|
+
const errorRecord = error;
|
|
182
|
+
const message = typeof errorRecord?.message === "string"
|
|
183
|
+
? errorRecord.message
|
|
184
|
+
: "Unknown error";
|
|
185
|
+
if (message.includes("Invalid API key") ||
|
|
186
|
+
message.includes("Authentication") ||
|
|
187
|
+
message.includes("401")) {
|
|
188
|
+
return new Error("Invalid DeepSeek API key. Please check your DEEPSEEK_API_KEY environment variable.");
|
|
189
|
+
}
|
|
190
|
+
if (message.includes("rate limit") || message.includes("429")) {
|
|
191
|
+
return new Error("DeepSeek rate limit exceeded");
|
|
192
|
+
}
|
|
193
|
+
if (message.includes("Insufficient Balance") ||
|
|
194
|
+
message.includes("insufficient_balance") ||
|
|
195
|
+
message.includes("402")) {
|
|
196
|
+
return new Error("DeepSeek account has insufficient balance. Top up at https://platform.deepseek.com/usage");
|
|
197
|
+
}
|
|
198
|
+
if (message.includes("model_not_found") || message.includes("404")) {
|
|
199
|
+
return new Error(`DeepSeek model '${this.modelName}' not found. Use 'deepseek-chat' or 'deepseek-reasoner'.`);
|
|
200
|
+
}
|
|
201
|
+
return new Error(`DeepSeek error: ${message}`);
|
|
202
|
+
}
|
|
203
|
+
async validateConfiguration() {
|
|
204
|
+
return typeof this.apiKey === "string" && this.apiKey.trim().length > 0;
|
|
205
|
+
}
|
|
206
|
+
getConfiguration() {
|
|
207
|
+
return {
|
|
208
|
+
provider: this.providerName,
|
|
209
|
+
model: this.modelName,
|
|
210
|
+
defaultModel: getDefaultDeepSeekModel(),
|
|
211
|
+
baseURL: this.baseURL,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
export default DeepSeekProvider;
|
|
@@ -14,3 +14,7 @@ export { HuggingFaceProvider as HuggingFace } from "./huggingFace.js";
|
|
|
14
14
|
export { OllamaProvider as Ollama } from "./ollama.js";
|
|
15
15
|
export { MistralProvider as MistralAI } from "./mistral.js";
|
|
16
16
|
export { LiteLLMProvider as LiteLLM } from "./litellm.js";
|
|
17
|
+
export { DeepSeekProvider as DeepSeek } from "./deepseek.js";
|
|
18
|
+
export { NvidiaNimProvider as NvidiaNim } from "./nvidiaNim.js";
|
|
19
|
+
export { LMStudioProvider as LMStudio } from "./lmStudio.js";
|
|
20
|
+
export { LlamaCppProvider as LlamaCpp } from "./llamaCpp.js";
|
package/dist/providers/index.js
CHANGED
|
@@ -14,3 +14,7 @@ export { HuggingFaceProvider as HuggingFace } from "./huggingFace.js";
|
|
|
14
14
|
export { OllamaProvider as Ollama } from "./ollama.js";
|
|
15
15
|
export { MistralProvider as MistralAI } from "./mistral.js";
|
|
16
16
|
export { LiteLLMProvider as LiteLLM } from "./litellm.js";
|
|
17
|
+
export { DeepSeekProvider as DeepSeek } from "./deepseek.js";
|
|
18
|
+
export { NvidiaNimProvider as NvidiaNim } from "./nvidiaNim.js";
|
|
19
|
+
export { LMStudioProvider as LMStudio } from "./lmStudio.js";
|
|
20
|
+
export { LlamaCppProvider as LlamaCpp } from "./llamaCpp.js";
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type LanguageModel } from "ai";
|
|
2
|
+
import type { AIProviderName } from "../constants/enums.js";
|
|
3
|
+
import { BaseProvider } from "../core/baseProvider.js";
|
|
4
|
+
import type { NeurolinkCredentials, StreamOptions, StreamResult, ValidationSchema } from "../types/index.js";
|
|
5
|
+
/**
|
|
6
|
+
* llama.cpp Provider
|
|
7
|
+
* Wraps a llama-server process (https://github.com/ggerganov/llama.cpp) that
|
|
8
|
+
* exposes an OpenAI-compatible API at http://localhost:8080/v1 by default.
|
|
9
|
+
* llama-server hosts ONE model loaded at startup; /v1/models returns just that.
|
|
10
|
+
*/
|
|
11
|
+
export declare class LlamaCppProvider extends BaseProvider {
|
|
12
|
+
private model?;
|
|
13
|
+
private readonly requestedModelName?;
|
|
14
|
+
private baseURL;
|
|
15
|
+
private apiKey;
|
|
16
|
+
private discoveredModel?;
|
|
17
|
+
private llamaCppClient;
|
|
18
|
+
constructor(modelName?: string, sdk?: unknown, _region?: string, credentials?: NeurolinkCredentials["llamacpp"]);
|
|
19
|
+
private getAvailableModels;
|
|
20
|
+
protected getAISDKModel(signal?: AbortSignal): Promise<LanguageModel>;
|
|
21
|
+
protected executeStream(options: StreamOptions, _analysisSchema?: ValidationSchema): Promise<StreamResult>;
|
|
22
|
+
private executeStreamInner;
|
|
23
|
+
protected getProviderName(): AIProviderName;
|
|
24
|
+
protected getDefaultModel(): string;
|
|
25
|
+
protected formatProviderError(error: unknown): Error;
|
|
26
|
+
validateConfiguration(): Promise<boolean>;
|
|
27
|
+
getConfiguration(): {
|
|
28
|
+
provider: AIProviderName;
|
|
29
|
+
model: string;
|
|
30
|
+
defaultModel: string;
|
|
31
|
+
baseURL: string;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export default LlamaCppProvider;
|