@juspay/neurolink 9.68.17 → 9.68.19
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 +4 -0
- package/dist/browser/neurolink.min.js +552 -584
- package/dist/lib/providers/mistral.d.ts +20 -28
- package/dist/lib/providers/mistral.js +61 -136
- package/dist/lib/providers/openRouter.d.ts +43 -28
- package/dist/lib/providers/openRouter.js +102 -298
- package/dist/lib/types/providers.d.ts +1 -0
- package/dist/providers/mistral.d.ts +20 -28
- package/dist/providers/mistral.js +61 -136
- package/dist/providers/openRouter.d.ts +43 -28
- package/dist/providers/openRouter.js +102 -298
- package/dist/types/providers.d.ts +1 -0
- package/package.json +1 -1
|
@@ -1,135 +1,64 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { DEFAULT_MAX_STEPS } from "../core/constants.js";
|
|
4
|
-
import { streamAnalyticsCollector } from "../core/streamAnalytics.js";
|
|
5
|
-
import { isNeuroLink } from "../neurolink.js";
|
|
6
|
-
import { createProxyFetch } from "../proxy/proxyFetch.js";
|
|
7
|
-
import { AuthenticationError, NetworkError, ProviderError, RateLimitError, } from "../types/index.js";
|
|
8
|
-
import { emitToolEndFromStepFinish } from "../utils/toolEndEmitter.js";
|
|
1
|
+
import { MistralModels } from "../constants/enums.js";
|
|
2
|
+
import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../types/index.js";
|
|
9
3
|
import { logger } from "../utils/logger.js";
|
|
4
|
+
import { redactUrlCredentials } from "../utils/logSanitize.js";
|
|
10
5
|
import { createMistralConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
import { stepCountIs } from "../utils/tool.js";
|
|
15
|
-
import { streamText } from "../utils/generation.js";
|
|
16
|
-
// Configuration helpers - now using consolidated utility
|
|
6
|
+
import { TimeoutError } from "../utils/timeout.js";
|
|
7
|
+
import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
|
|
8
|
+
const MISTRAL_DEFAULT_BASE_URL = "https://api.mistral.ai/v1";
|
|
17
9
|
const getMistralApiKey = () => {
|
|
18
10
|
return validateApiKey(createMistralConfig());
|
|
19
11
|
};
|
|
20
12
|
const getDefaultMistralModel = () => {
|
|
21
|
-
//
|
|
22
|
-
return getProviderModel("MISTRAL_MODEL",
|
|
13
|
+
// Vision-capable Mistral Small (June 2025) with multimodal support.
|
|
14
|
+
return getProviderModel("MISTRAL_MODEL", MistralModels.MISTRAL_SMALL_2506);
|
|
23
15
|
};
|
|
24
16
|
/**
|
|
25
|
-
* Mistral AI Provider
|
|
26
|
-
*
|
|
17
|
+
* Mistral AI Provider — direct HTTP, no AI SDK.
|
|
18
|
+
*
|
|
19
|
+
* OpenAI-compatible chat completions at api.mistral.ai/v1. All request/stream/
|
|
20
|
+
* tool-loop orchestration lives in `OpenAIChatCompletionsProvider`; this class
|
|
21
|
+
* only declares configuration and the provider-specific error mapping.
|
|
22
|
+
*
|
|
23
|
+
* Mistral's `/chat/completions` accepts `response_format: { type:
|
|
24
|
+
* "json_schema" }` on current models (mistral-small-2506 and newer), so no
|
|
25
|
+
* structured-output downgrade is needed — the base client's default
|
|
26
|
+
* pass-through is correct.
|
|
27
|
+
*
|
|
28
|
+
* @see https://docs.mistral.ai/api/
|
|
27
29
|
*/
|
|
28
|
-
export class MistralProvider extends
|
|
29
|
-
model;
|
|
30
|
+
export class MistralProvider extends OpenAIChatCompletionsProvider {
|
|
30
31
|
constructor(modelName, sdk, _region, credentials) {
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
//
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
32
|
+
// Trim the override before applying precedence. A blank/whitespace
|
|
33
|
+
// `credentials.apiKey` must NOT bypass `getMistralApiKey()` — that would
|
|
34
|
+
// build a client with an unusable bearer token and fail at request time
|
|
35
|
+
// with a confusing 401 instead of at construction time.
|
|
36
|
+
const overrideApiKey = credentials?.apiKey?.trim();
|
|
37
|
+
const apiKey = overrideApiKey && overrideApiKey.length > 0
|
|
38
|
+
? overrideApiKey
|
|
39
|
+
: getMistralApiKey();
|
|
40
|
+
// Treat blank/whitespace overrides as unset so an empty
|
|
41
|
+
// `credentials.baseURL` or `MISTRAL_BASE_URL=` cannot silently override
|
|
42
|
+
// the default with "" (mirrors the apiKey precedence above).
|
|
43
|
+
const baseURL = credentials?.baseURL?.trim() ||
|
|
44
|
+
process.env.MISTRAL_BASE_URL?.trim() ||
|
|
45
|
+
MISTRAL_DEFAULT_BASE_URL;
|
|
46
|
+
super("mistral", modelName, sdk, { baseURL, apiKey });
|
|
47
|
+
logger.debug("Mistral Provider initialized", {
|
|
42
48
|
modelName: this.modelName,
|
|
43
49
|
providerName: this.providerName,
|
|
50
|
+
baseURL: redactUrlCredentials(this.config.baseURL),
|
|
44
51
|
});
|
|
45
52
|
}
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const startTime = Date.now();
|
|
50
|
-
const timeout = this.getTimeout(options);
|
|
51
|
-
const timeoutController = createTimeoutController(timeout, this.providerName, "stream");
|
|
52
|
-
try {
|
|
53
|
-
// Get tools - options.tools is pre-merged by BaseProvider.stream()
|
|
54
|
-
const shouldUseTools = !options.disableTools && this.supportsTools();
|
|
55
|
-
const tools = shouldUseTools
|
|
56
|
-
? options.tools || (await this.getAllTools())
|
|
57
|
-
: {};
|
|
58
|
-
// Build message array from options with multimodal support
|
|
59
|
-
// Using protected helper from BaseProvider to eliminate code duplication
|
|
60
|
-
const messages = await this.buildMessagesForStream(options);
|
|
61
|
-
const model = await this.getAISDKModelWithMiddleware(options); // This is where network connection happens!
|
|
62
|
-
// Reviewer follow-up: capture upstream provider errors via onError
|
|
63
|
-
// so the post-stream NoOutput sentinel carries the real cause.
|
|
64
|
-
let capturedProviderError;
|
|
65
|
-
const result = await streamText({
|
|
66
|
-
model,
|
|
67
|
-
messages: messages,
|
|
68
|
-
temperature: options.temperature,
|
|
69
|
-
maxOutputTokens: options.maxTokens, // No default limit - unlimited unless specified
|
|
70
|
-
tools,
|
|
71
|
-
stopWhen: stepCountIs(options.maxSteps || DEFAULT_MAX_STEPS),
|
|
72
|
-
toolChoice: resolveToolChoice(options, tools, shouldUseTools),
|
|
73
|
-
abortSignal: composeAbortSignals(options.abortSignal, timeoutController?.controller.signal),
|
|
74
|
-
experimental_telemetry: this.telemetryHandler.getTelemetryConfig(options),
|
|
75
|
-
experimental_repairToolCall: this.getToolCallRepairFn(options),
|
|
76
|
-
onError: (event) => {
|
|
77
|
-
capturedProviderError = event.error;
|
|
78
|
-
logger.error("Mistral: Stream error", {
|
|
79
|
-
error: event.error instanceof Error
|
|
80
|
-
? event.error.message
|
|
81
|
-
: String(event.error),
|
|
82
|
-
});
|
|
83
|
-
},
|
|
84
|
-
onStepFinish: ({ toolCalls, toolResults }) => {
|
|
85
|
-
emitToolEndFromStepFinish(this.neurolink?.getEventEmitter(), toolResults);
|
|
86
|
-
this.handleToolExecutionStorage(toolCalls, toolResults, options, new Date()).catch((error) => {
|
|
87
|
-
logger.warn("[MistralProvider] Failed to store tool executions", {
|
|
88
|
-
provider: this.providerName,
|
|
89
|
-
error: error instanceof Error ? error.message : String(error),
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
},
|
|
93
|
-
});
|
|
94
|
-
timeoutController?.cleanup();
|
|
95
|
-
// Transform string stream to content object stream using BaseProvider method
|
|
96
|
-
const transformedStream = this.createTextStream(result, () => capturedProviderError);
|
|
97
|
-
// Create analytics promise that resolves after stream completion
|
|
98
|
-
const analyticsPromise = streamAnalyticsCollector.createAnalytics(this.providerName, this.modelName, toAnalyticsStreamResult(result), Date.now() - startTime, {
|
|
99
|
-
requestId: `mistral-stream-${Date.now()}`,
|
|
100
|
-
streamingMode: true,
|
|
101
|
-
});
|
|
102
|
-
return {
|
|
103
|
-
stream: transformedStream,
|
|
104
|
-
provider: this.providerName,
|
|
105
|
-
model: this.modelName,
|
|
106
|
-
analytics: analyticsPromise,
|
|
107
|
-
metadata: {
|
|
108
|
-
startTime,
|
|
109
|
-
streamId: `mistral-${Date.now()}`,
|
|
110
|
-
},
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
catch (error) {
|
|
114
|
-
timeoutController?.cleanup();
|
|
115
|
-
throw this.handleProviderError(error);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
// ===================
|
|
119
|
-
// ABSTRACT METHOD IMPLEMENTATIONS
|
|
120
|
-
// ===================
|
|
53
|
+
// ===========================================================================
|
|
54
|
+
// Abstract hooks (required)
|
|
55
|
+
// ===========================================================================
|
|
121
56
|
getProviderName() {
|
|
122
|
-
return
|
|
57
|
+
return "mistral";
|
|
123
58
|
}
|
|
124
59
|
getDefaultModel() {
|
|
125
60
|
return getDefaultMistralModel();
|
|
126
61
|
}
|
|
127
|
-
/**
|
|
128
|
-
* Returns the Vercel AI SDK model instance for Mistral
|
|
129
|
-
*/
|
|
130
|
-
getAISDKModel() {
|
|
131
|
-
return this.model;
|
|
132
|
-
}
|
|
133
62
|
formatProviderError(error) {
|
|
134
63
|
if (error instanceof TimeoutError) {
|
|
135
64
|
return new NetworkError(`Request timed out: ${error.message}`, "mistral");
|
|
@@ -139,35 +68,31 @@ export class MistralProvider extends BaseProvider {
|
|
|
139
68
|
? errorRecord.message
|
|
140
69
|
: "Unknown error";
|
|
141
70
|
if (message.includes("API_KEY_INVALID") ||
|
|
142
|
-
message.includes("Invalid API key")
|
|
71
|
+
message.includes("Invalid API key") ||
|
|
72
|
+
message.includes("Unauthorized") ||
|
|
73
|
+
message.includes("401")) {
|
|
143
74
|
return new AuthenticationError("Invalid Mistral API key. Please check your MISTRAL_API_KEY environment variable.", "mistral");
|
|
144
75
|
}
|
|
145
|
-
if (message.includes("
|
|
76
|
+
if (message.includes("rate limit") ||
|
|
77
|
+
message.includes("Rate limit") ||
|
|
78
|
+
message.includes("429")) {
|
|
146
79
|
return new RateLimitError("Mistral rate limit exceeded", "mistral");
|
|
147
80
|
}
|
|
81
|
+
if (message.includes("model_not_found") || message.includes("404")) {
|
|
82
|
+
return new InvalidModelError(`Mistral model '${this.modelName}' not found.`, "mistral");
|
|
83
|
+
}
|
|
148
84
|
return new ProviderError(`Mistral error: ${message}`, "mistral");
|
|
149
85
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
getMistralApiKey();
|
|
156
|
-
return true;
|
|
157
|
-
}
|
|
158
|
-
catch {
|
|
159
|
-
return false;
|
|
160
|
-
}
|
|
86
|
+
// ===========================================================================
|
|
87
|
+
// Optional hooks
|
|
88
|
+
// ===========================================================================
|
|
89
|
+
getFallbackModelName() {
|
|
90
|
+
return MistralModels.MISTRAL_SMALL_2506;
|
|
161
91
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
provider: this.providerName,
|
|
168
|
-
model: this.modelName,
|
|
169
|
-
defaultModel: getDefaultMistralModel(),
|
|
170
|
-
};
|
|
92
|
+
getFallbackModels() {
|
|
93
|
+
return [
|
|
94
|
+
MistralModels.MISTRAL_SMALL_2506,
|
|
95
|
+
MistralModels.MISTRAL_LARGE_LATEST,
|
|
96
|
+
];
|
|
171
97
|
}
|
|
172
98
|
}
|
|
173
|
-
export default MistralProvider;
|
|
@@ -1,60 +1,75 @@
|
|
|
1
|
-
import type { ZodType } from "zod";
|
|
2
1
|
import { AIProviderName } from "../constants/enums.js";
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import type { LanguageModel, Schema } from "../types/index.js";
|
|
2
|
+
import type { NeurolinkCredentials } from "../types/index.js";
|
|
3
|
+
import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
|
|
6
4
|
/**
|
|
7
|
-
* OpenRouter Provider
|
|
8
|
-
*
|
|
5
|
+
* OpenRouter Provider — direct HTTP, no AI SDK.
|
|
6
|
+
*
|
|
7
|
+
* OpenAI-compatible unified gateway to 300+ models from 60+ providers. All
|
|
8
|
+
* request/stream/tool-loop orchestration lives in
|
|
9
|
+
* `OpenAIChatCompletionsProvider`; this class declares configuration plus the
|
|
10
|
+
* OpenRouter-specific behaviour:
|
|
11
|
+
*
|
|
12
|
+
* 1. Attribution headers — optional `HTTP-Referer` / `X-Title` (from
|
|
13
|
+
* `OPENROUTER_REFERER` / `OPENROUTER_APP_NAME`) are merged into every
|
|
14
|
+
* request via `getAuthHeaders` so usage shows up on the openrouter.ai
|
|
15
|
+
* activity dashboard.
|
|
16
|
+
* 2. Per-model tool gating — OpenRouter proxies many models with varying
|
|
17
|
+
* tool support, so `supportsTools()` consults a cached capability set
|
|
18
|
+
* (populated by `cacheModelCapabilities()`) and falls back to a
|
|
19
|
+
* conservative known-capable pattern list.
|
|
20
|
+
* 3. Dynamic model discovery — `getAvailableModels()` fetches the live
|
|
21
|
+
* `/models` list (10-minute cache) with a hardcoded fallback.
|
|
22
|
+
*
|
|
23
|
+
* @see https://openrouter.ai/docs
|
|
9
24
|
*/
|
|
10
|
-
export declare class OpenRouterProvider extends
|
|
11
|
-
private
|
|
12
|
-
private
|
|
13
|
-
private config;
|
|
25
|
+
export declare class OpenRouterProvider extends OpenAIChatCompletionsProvider {
|
|
26
|
+
private readonly referer?;
|
|
27
|
+
private readonly appName?;
|
|
14
28
|
private static modelsCache;
|
|
15
29
|
private static modelsCacheTime;
|
|
16
30
|
private static readonly MODELS_CACHE_DURATION;
|
|
17
31
|
private static toolCapableModels;
|
|
18
32
|
private static capabilitiesCached;
|
|
19
|
-
constructor(modelName?: string, sdk?: unknown, _region?: string, credentials?:
|
|
20
|
-
apiKey?: string;
|
|
21
|
-
baseURL?: string;
|
|
22
|
-
});
|
|
33
|
+
constructor(modelName?: string, sdk?: unknown, _region?: string, credentials?: NeurolinkCredentials["openrouter"]);
|
|
23
34
|
protected getProviderName(): AIProviderName;
|
|
24
35
|
protected getDefaultModel(): string;
|
|
36
|
+
protected formatProviderError(error: unknown): Error;
|
|
37
|
+
protected getFallbackModelName(): string;
|
|
25
38
|
/**
|
|
26
|
-
*
|
|
39
|
+
* Attribution headers are merged into every request alongside the bearer
|
|
40
|
+
* token so OpenRouter can attribute usage on its activity dashboard.
|
|
27
41
|
*/
|
|
28
|
-
protected
|
|
29
|
-
formatProviderError(error: unknown): Error;
|
|
42
|
+
protected getAuthHeaders(): Record<string, string>;
|
|
30
43
|
/**
|
|
31
|
-
* OpenRouter
|
|
32
|
-
*
|
|
44
|
+
* OpenRouter proxies models with varying tool support. Use cached
|
|
45
|
+
* capabilities when available (populated by `cacheModelCapabilities()`),
|
|
46
|
+
* otherwise fall back to a conservative known-capable pattern list and
|
|
47
|
+
* disable tools for unknown models.
|
|
33
48
|
*/
|
|
34
49
|
supportsTools(): boolean;
|
|
35
50
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
51
|
+
* Models/capabilities endpoint, derived from the configured `baseURL` so a
|
|
52
|
+
* custom OpenRouter-compatible gateway is honoured for discovery too.
|
|
38
53
|
*/
|
|
39
|
-
|
|
54
|
+
private getModelsUrl;
|
|
40
55
|
/**
|
|
41
|
-
* Get available models from OpenRouter
|
|
42
|
-
*
|
|
56
|
+
* Get available models from the OpenRouter `/models` endpoint, with a
|
|
57
|
+
* 10-minute cache and a hardcoded fallback when the fetch fails.
|
|
43
58
|
*/
|
|
44
59
|
getAvailableModels(): Promise<string[]>;
|
|
45
60
|
/**
|
|
46
|
-
* Fetch available models from OpenRouter
|
|
61
|
+
* Fetch available models from the OpenRouter `/models` endpoint.
|
|
47
62
|
* @private
|
|
48
63
|
*/
|
|
49
64
|
private fetchModelsFromAPI;
|
|
50
65
|
/**
|
|
51
|
-
* Type guard to validate the models API response structure
|
|
66
|
+
* Type guard to validate the models API response structure.
|
|
52
67
|
* @private
|
|
53
68
|
*/
|
|
54
69
|
private isValidModelsResponse;
|
|
55
70
|
/**
|
|
56
|
-
* Fetch and cache model capabilities from OpenRouter
|
|
57
|
-
* Call this to enable accurate tool support detection
|
|
71
|
+
* Fetch and cache model capabilities from the OpenRouter `/models` endpoint.
|
|
72
|
+
* Call this to enable accurate per-model tool support detection.
|
|
58
73
|
*/
|
|
59
74
|
cacheModelCapabilities(): Promise<void>;
|
|
60
75
|
}
|