@juspay/neurolink 9.68.15 → 9.68.17
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 +8 -0
- package/dist/browser/neurolink.min.js +333 -333
- package/dist/lib/providers/cloudflare.js +2 -1
- package/dist/lib/providers/cohere.d.ts +18 -16
- package/dist/lib/providers/cohere.js +76 -153
- package/dist/lib/providers/deepseek.js +2 -1
- package/dist/lib/providers/fireworks.js +2 -1
- package/dist/lib/providers/groq.js +2 -1
- package/dist/lib/providers/huggingFace.js +2 -1
- package/dist/lib/providers/litellm.js +2 -1
- package/dist/lib/providers/llamaCpp.js +1 -6
- package/dist/lib/providers/lmStudio.js +3 -2
- package/dist/lib/providers/nvidiaNim.js +2 -1
- package/dist/lib/providers/openAI.js +2 -1
- package/dist/lib/providers/openaiCompatible.js +3 -2
- package/dist/lib/providers/perplexity.js +2 -1
- package/dist/lib/providers/togetherAi.js +2 -1
- package/dist/lib/providers/xai.js +2 -1
- package/dist/lib/utils/logSanitize.d.ts +14 -0
- package/dist/lib/utils/logSanitize.js +16 -0
- package/dist/providers/cloudflare.js +2 -1
- package/dist/providers/cohere.d.ts +18 -16
- package/dist/providers/cohere.js +76 -153
- package/dist/providers/deepseek.js +2 -1
- package/dist/providers/fireworks.js +2 -1
- package/dist/providers/groq.js +2 -1
- package/dist/providers/huggingFace.js +2 -1
- package/dist/providers/litellm.js +2 -1
- package/dist/providers/llamaCpp.js +1 -6
- package/dist/providers/lmStudio.js +3 -2
- package/dist/providers/nvidiaNim.js +2 -1
- package/dist/providers/openAI.js +2 -1
- package/dist/providers/openaiCompatible.js +3 -2
- package/dist/providers/perplexity.js +2 -1
- package/dist/providers/togetherAi.js +2 -1
- package/dist/providers/xai.js +2 -1
- package/dist/utils/logSanitize.d.ts +14 -0
- package/dist/utils/logSanitize.js +16 -0
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { CloudflareModels } from "../constants/enums.js";
|
|
2
2
|
import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../types/index.js";
|
|
3
3
|
import { logger } from "../utils/logger.js";
|
|
4
|
+
import { redactUrlCredentials } from "../utils/logSanitize.js";
|
|
4
5
|
import { createCloudflareConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
|
|
5
6
|
import { TimeoutError } from "../utils/timeout.js";
|
|
6
7
|
import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
|
|
@@ -44,7 +45,7 @@ export class CloudflareProvider extends OpenAIChatCompletionsProvider {
|
|
|
44
45
|
logger.debug("Cloudflare Workers AI Provider initialized", {
|
|
45
46
|
modelName: this.modelName,
|
|
46
47
|
providerName: this.providerName,
|
|
47
|
-
baseURL: this.config.baseURL,
|
|
48
|
+
baseURL: redactUrlCredentials(this.config.baseURL),
|
|
48
49
|
});
|
|
49
50
|
}
|
|
50
51
|
getProviderName() {
|
|
@@ -1,27 +1,26 @@
|
|
|
1
1
|
import type { AIProviderName } from "../constants/enums.js";
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import type { LanguageModel } from "../types/index.js";
|
|
2
|
+
import type { NeurolinkCredentials } from "../types/index.js";
|
|
3
|
+
import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
|
|
5
4
|
/**
|
|
6
|
-
* Cohere Provider
|
|
5
|
+
* Cohere Provider — direct HTTP, no AI SDK.
|
|
7
6
|
*
|
|
8
|
-
* Routes Command R / Command R+ chat completions through Cohere's
|
|
9
|
-
* compatible endpoint
|
|
10
|
-
*
|
|
11
|
-
*
|
|
7
|
+
* Routes Command R / Command R+ chat completions through Cohere's
|
|
8
|
+
* OpenAI-compatible endpoint at /compatibility/v1. All request/stream/
|
|
9
|
+
* tool-loop orchestration lives in `OpenAIChatCompletionsProvider`; this
|
|
10
|
+
* class only declares configuration and provider-specific error mapping.
|
|
11
|
+
*
|
|
12
|
+
* Embed v3 is exposed via `embed()` / `embedMany()` backed by a native
|
|
13
|
+
* POST to /v2/embed (the compatibility path is chat-only).
|
|
12
14
|
*
|
|
13
15
|
* @see https://docs.cohere.com/docs/compatibility-api
|
|
16
|
+
* @see https://docs.cohere.com/reference/embed
|
|
14
17
|
*/
|
|
15
|
-
export declare class CohereProvider extends
|
|
16
|
-
private model;
|
|
17
|
-
private apiKey;
|
|
18
|
-
private baseURL;
|
|
18
|
+
export declare class CohereProvider extends OpenAIChatCompletionsProvider {
|
|
19
19
|
constructor(modelName?: string, sdk?: unknown, _region?: string, credentials?: NeurolinkCredentials["cohere"]);
|
|
20
|
-
protected executeStream(options: StreamOptions, _analysisSchema?: ValidationSchema): Promise<StreamResult>;
|
|
21
|
-
private executeStreamInner;
|
|
22
20
|
protected getProviderName(): AIProviderName;
|
|
23
21
|
protected getDefaultModel(): string;
|
|
24
|
-
protected
|
|
22
|
+
protected getFallbackModelName(): string;
|
|
23
|
+
protected getFallbackModels(): string[];
|
|
25
24
|
protected formatProviderError(error: unknown): Error;
|
|
26
25
|
validateConfiguration(): Promise<boolean>;
|
|
27
26
|
getConfiguration(): {
|
|
@@ -46,7 +45,10 @@ export declare class CohereProvider extends BaseProvider {
|
|
|
46
45
|
/**
|
|
47
46
|
* Batch embedding via Cohere's native /v2/embed endpoint. Cohere caps at
|
|
48
47
|
* 96 inputs per request; larger batches are chunked.
|
|
48
|
+
*
|
|
49
|
+
* Partial failures are not surfaced: if any chunk request fails the whole
|
|
50
|
+
* call rejects and already-embedded chunks are discarded — callers should
|
|
51
|
+
* retry the full input.
|
|
49
52
|
*/
|
|
50
53
|
embedMany(texts: string[], modelName?: string): Promise<number[][]>;
|
|
51
54
|
}
|
|
52
|
-
export default CohereProvider;
|
|
@@ -1,154 +1,62 @@
|
|
|
1
|
-
import { createOpenAI } from "@ai-sdk/openai";
|
|
2
1
|
import { CohereModels } from "../constants/enums.js";
|
|
3
|
-
import { BaseProvider } from "../core/baseProvider.js";
|
|
4
|
-
import { DEFAULT_MAX_STEPS } from "../core/constants.js";
|
|
5
|
-
import { streamAnalyticsCollector } from "../core/streamAnalytics.js";
|
|
6
|
-
import { isNeuroLink } from "../neurolink.js";
|
|
7
|
-
import { createLoggingFetch } from "../utils/loggingFetch.js";
|
|
8
|
-
import { tracers, ATTR, withClientStreamSpan } from "../telemetry/index.js";
|
|
9
2
|
import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../types/index.js";
|
|
10
3
|
import { logger } from "../utils/logger.js";
|
|
4
|
+
import { redactUrlCredentials } from "../utils/logSanitize.js";
|
|
5
|
+
import { createProxyFetch } from "../proxy/proxyFetch.js";
|
|
11
6
|
import { createCohereConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import { toAnalyticsStreamResult } from "./providerTypeUtils.js";
|
|
16
|
-
import { stepCountIs } from "../utils/tool.js";
|
|
17
|
-
import { streamText } from "../utils/generation.js";
|
|
18
|
-
/**
|
|
19
|
-
* Cohere uses an OpenAI-compatible endpoint at /compatibility/v1 that
|
|
20
|
-
* accepts the same chat-completions shape. Embeddings + Rerank live on
|
|
21
|
-
* the native API and are not exposed through this LLM provider class
|
|
22
|
-
* (use the Cohere SDK directly or the embed/rerank routes when added).
|
|
23
|
-
*/
|
|
7
|
+
import { createTimeoutController, TimeoutError } from "../utils/timeout.js";
|
|
8
|
+
import { stripTrailingSlash } from "./openaiChatCompletionsClient.js";
|
|
9
|
+
import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
|
|
24
10
|
const COHERE_DEFAULT_BASE_URL = "https://api.cohere.com/compatibility/v1";
|
|
25
11
|
const getCohereApiKey = () => validateApiKey(createCohereConfig());
|
|
26
12
|
const getDefaultCohereModel = () => getProviderModel("COHERE_MODEL", CohereModels.COMMAND_R_PLUS);
|
|
27
13
|
/**
|
|
28
|
-
* Cohere Provider
|
|
14
|
+
* Cohere Provider — direct HTTP, no AI SDK.
|
|
15
|
+
*
|
|
16
|
+
* Routes Command R / Command R+ chat completions through Cohere's
|
|
17
|
+
* OpenAI-compatible endpoint at /compatibility/v1. All request/stream/
|
|
18
|
+
* tool-loop orchestration lives in `OpenAIChatCompletionsProvider`; this
|
|
19
|
+
* class only declares configuration and provider-specific error mapping.
|
|
29
20
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* accessed via the Cohere native SDK / dedicated embedding routes (out of
|
|
33
|
-
* scope for the LLM provider).
|
|
21
|
+
* Embed v3 is exposed via `embed()` / `embedMany()` backed by a native
|
|
22
|
+
* POST to /v2/embed (the compatibility path is chat-only).
|
|
34
23
|
*
|
|
35
24
|
* @see https://docs.cohere.com/docs/compatibility-api
|
|
25
|
+
* @see https://docs.cohere.com/reference/embed
|
|
36
26
|
*/
|
|
37
|
-
export class CohereProvider extends
|
|
38
|
-
model;
|
|
39
|
-
apiKey;
|
|
40
|
-
baseURL;
|
|
27
|
+
export class CohereProvider extends OpenAIChatCompletionsProvider {
|
|
41
28
|
constructor(modelName, sdk, _region, credentials) {
|
|
42
|
-
const validatedNeurolink = isNeuroLink(sdk) ? sdk : undefined;
|
|
43
|
-
super(modelName, "cohere", validatedNeurolink);
|
|
44
29
|
const overrideApiKey = credentials?.apiKey?.trim();
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
COHERE_DEFAULT_BASE_URL;
|
|
53
|
-
const cohere = createOpenAI({
|
|
54
|
-
apiKey: this.apiKey,
|
|
55
|
-
baseURL: this.baseURL,
|
|
56
|
-
fetch: createLoggingFetch("cohere"),
|
|
57
|
-
});
|
|
58
|
-
this.model = cohere.chat(this.modelName);
|
|
30
|
+
const apiKey = overrideApiKey && overrideApiKey.length > 0
|
|
31
|
+
? overrideApiKey
|
|
32
|
+
: getCohereApiKey();
|
|
33
|
+
const baseURL = credentials?.baseURL?.trim() ||
|
|
34
|
+
process.env.COHERE_BASE_URL?.trim() ||
|
|
35
|
+
COHERE_DEFAULT_BASE_URL;
|
|
36
|
+
super("cohere", modelName, sdk, { baseURL, apiKey });
|
|
59
37
|
logger.debug("Cohere Provider initialized", {
|
|
60
38
|
modelName: this.modelName,
|
|
61
39
|
providerName: this.providerName,
|
|
62
|
-
baseURL: this.baseURL,
|
|
40
|
+
baseURL: redactUrlCredentials(this.config.baseURL),
|
|
63
41
|
});
|
|
64
42
|
}
|
|
65
|
-
async executeStream(options, _analysisSchema) {
|
|
66
|
-
// withClientStreamSpan: keeps the span open until the consumer reaches
|
|
67
|
-
// end-of-stream / error, so the recorded duration reflects the actual
|
|
68
|
-
// stream lifetime instead of just setup.
|
|
69
|
-
return withClientStreamSpan({
|
|
70
|
-
name: "neurolink.provider.stream",
|
|
71
|
-
tracer: tracers.provider,
|
|
72
|
-
attributes: {
|
|
73
|
-
[ATTR.GEN_AI_SYSTEM]: "cohere",
|
|
74
|
-
[ATTR.GEN_AI_MODEL]: this.modelName,
|
|
75
|
-
[ATTR.GEN_AI_OPERATION]: "stream",
|
|
76
|
-
[ATTR.NL_STREAM_MODE]: true,
|
|
77
|
-
},
|
|
78
|
-
}, async () => this.executeStreamInner(options), (r) => r.stream, (r, wrapped) => ({ ...r, stream: wrapped }));
|
|
79
|
-
}
|
|
80
|
-
async executeStreamInner(options) {
|
|
81
|
-
this.validateStreamOptions(options);
|
|
82
|
-
// Resolve per-call credentials first, then fall back to instance-level.
|
|
83
|
-
const perCallCreds = options.credentials?.cohere;
|
|
84
|
-
const effectiveApiKey = perCallCreds?.apiKey?.trim() || this.apiKey;
|
|
85
|
-
const effectiveBaseURL = perCallCreds?.baseURL || this.baseURL;
|
|
86
|
-
const startTime = Date.now();
|
|
87
|
-
const timeout = this.getTimeout(options);
|
|
88
|
-
const timeoutController = createTimeoutController(timeout, this.providerName, "stream");
|
|
89
|
-
try {
|
|
90
|
-
const shouldUseTools = !options.disableTools && this.supportsTools();
|
|
91
|
-
const tools = shouldUseTools
|
|
92
|
-
? options.tools || (await this.getAllTools())
|
|
93
|
-
: {};
|
|
94
|
-
const messages = await this.buildMessagesForStream(options);
|
|
95
|
-
// When per-call credentials differ from instance, build a fresh client.
|
|
96
|
-
const hasDifferentCreds = effectiveApiKey !== this.apiKey || effectiveBaseURL !== this.baseURL;
|
|
97
|
-
const model = hasDifferentCreds
|
|
98
|
-
? createOpenAI({
|
|
99
|
-
apiKey: effectiveApiKey,
|
|
100
|
-
baseURL: effectiveBaseURL,
|
|
101
|
-
fetch: createLoggingFetch("cohere"),
|
|
102
|
-
}).chat(this.modelName)
|
|
103
|
-
: await this.getAISDKModelWithMiddleware(options);
|
|
104
|
-
const result = await streamText({
|
|
105
|
-
model,
|
|
106
|
-
messages,
|
|
107
|
-
temperature: options.temperature,
|
|
108
|
-
maxOutputTokens: options.maxTokens,
|
|
109
|
-
tools,
|
|
110
|
-
stopWhen: stepCountIs(options.maxSteps || DEFAULT_MAX_STEPS),
|
|
111
|
-
toolChoice: resolveToolChoice(options, tools, shouldUseTools),
|
|
112
|
-
abortSignal: composeAbortSignals(options.abortSignal, timeoutController?.controller.signal),
|
|
113
|
-
experimental_telemetry: this.telemetryHandler.getTelemetryConfig(options),
|
|
114
|
-
experimental_repairToolCall: this.getToolCallRepairFn(options),
|
|
115
|
-
onStepFinish: ({ toolCalls, toolResults }) => {
|
|
116
|
-
emitToolEndFromStepFinish(this.neurolink?.getEventEmitter(), toolResults);
|
|
117
|
-
this.handleToolExecutionStorage(toolCalls, toolResults, options, new Date()).catch((error) => {
|
|
118
|
-
logger.warn("[CohereProvider] Failed to store tool executions", {
|
|
119
|
-
provider: this.providerName,
|
|
120
|
-
error: error instanceof Error ? error.message : String(error),
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
},
|
|
124
|
-
});
|
|
125
|
-
timeoutController?.cleanup();
|
|
126
|
-
const transformedStream = this.createTextStream(result);
|
|
127
|
-
const analyticsPromise = streamAnalyticsCollector.createAnalytics(this.providerName, this.modelName, toAnalyticsStreamResult(result), Date.now() - startTime, {
|
|
128
|
-
requestId: `cohere-stream-${Date.now()}`,
|
|
129
|
-
streamingMode: true,
|
|
130
|
-
});
|
|
131
|
-
return {
|
|
132
|
-
stream: transformedStream,
|
|
133
|
-
provider: this.providerName,
|
|
134
|
-
model: this.modelName,
|
|
135
|
-
analytics: analyticsPromise,
|
|
136
|
-
metadata: { startTime, streamId: `cohere-${Date.now()}` },
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
catch (error) {
|
|
140
|
-
timeoutController?.cleanup();
|
|
141
|
-
throw this.handleProviderError(error);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
43
|
getProviderName() {
|
|
145
|
-
return
|
|
44
|
+
return "cohere";
|
|
146
45
|
}
|
|
147
46
|
getDefaultModel() {
|
|
148
47
|
return getDefaultCohereModel();
|
|
149
48
|
}
|
|
150
|
-
|
|
151
|
-
return
|
|
49
|
+
getFallbackModelName() {
|
|
50
|
+
return CohereModels.COMMAND_R;
|
|
51
|
+
}
|
|
52
|
+
getFallbackModels() {
|
|
53
|
+
return [
|
|
54
|
+
CohereModels.COMMAND_A,
|
|
55
|
+
CohereModels.COMMAND_A_REASONING,
|
|
56
|
+
CohereModels.COMMAND_R_PLUS,
|
|
57
|
+
CohereModels.COMMAND_R,
|
|
58
|
+
CohereModels.COMMAND_R7B,
|
|
59
|
+
];
|
|
152
60
|
}
|
|
153
61
|
formatProviderError(error) {
|
|
154
62
|
if (error instanceof TimeoutError) {
|
|
@@ -176,14 +84,15 @@ export class CohereProvider extends BaseProvider {
|
|
|
176
84
|
return new ProviderError(`Cohere error: ${message}`, "cohere");
|
|
177
85
|
}
|
|
178
86
|
async validateConfiguration() {
|
|
179
|
-
return typeof this.apiKey === "string" &&
|
|
87
|
+
return (typeof this.config.apiKey === "string" &&
|
|
88
|
+
this.config.apiKey.trim().length > 0);
|
|
180
89
|
}
|
|
181
90
|
getConfiguration() {
|
|
182
91
|
return {
|
|
183
92
|
provider: this.providerName,
|
|
184
93
|
model: this.modelName,
|
|
185
94
|
defaultModel: getDefaultCohereModel(),
|
|
186
|
-
baseURL: this.baseURL,
|
|
95
|
+
baseURL: this.config.baseURL,
|
|
187
96
|
};
|
|
188
97
|
}
|
|
189
98
|
/**
|
|
@@ -210,45 +119,59 @@ export class CohereProvider extends BaseProvider {
|
|
|
210
119
|
/**
|
|
211
120
|
* Batch embedding via Cohere's native /v2/embed endpoint. Cohere caps at
|
|
212
121
|
* 96 inputs per request; larger batches are chunked.
|
|
122
|
+
*
|
|
123
|
+
* Partial failures are not surfaced: if any chunk request fails the whole
|
|
124
|
+
* call rejects and already-embedded chunks are discarded — callers should
|
|
125
|
+
* retry the full input.
|
|
213
126
|
*/
|
|
214
127
|
async embedMany(texts, modelName) {
|
|
215
128
|
if (texts.length === 0) {
|
|
216
129
|
return [];
|
|
217
130
|
}
|
|
218
131
|
const model = modelName ?? this.getDefaultEmbeddingModel();
|
|
219
|
-
|
|
132
|
+
// Strip the compatibility suffix to reach the native API root.
|
|
133
|
+
const baseUrl = stripTrailingSlash(this.config.baseURL.replace(/\/compatibility\/v\d+\/?$/, ""));
|
|
220
134
|
const url = `${baseUrl}/v2/embed`;
|
|
221
135
|
const BATCH_SIZE = 96;
|
|
222
136
|
const results = [];
|
|
137
|
+
const fetchImpl = createProxyFetch();
|
|
223
138
|
for (let i = 0; i < texts.length; i += BATCH_SIZE) {
|
|
224
139
|
const batch = texts.slice(i, i + BATCH_SIZE);
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
140
|
+
const timeoutController = createTimeoutController(30_000, this.providerName, "generate");
|
|
141
|
+
try {
|
|
142
|
+
const response = await fetchImpl(url, {
|
|
143
|
+
method: "POST",
|
|
144
|
+
headers: {
|
|
145
|
+
Authorization: `Bearer ${this.config.apiKey}`,
|
|
146
|
+
"Content-Type": "application/json",
|
|
147
|
+
},
|
|
148
|
+
body: JSON.stringify({
|
|
149
|
+
model,
|
|
150
|
+
texts: batch,
|
|
151
|
+
input_type: "search_document",
|
|
152
|
+
embedding_types: ["float"],
|
|
153
|
+
}),
|
|
154
|
+
...(timeoutController?.controller.signal
|
|
155
|
+
? { signal: timeoutController.controller.signal }
|
|
156
|
+
: {}),
|
|
157
|
+
});
|
|
158
|
+
if (!response.ok) {
|
|
159
|
+
const body = await response.text().catch(() => "");
|
|
160
|
+
throw this.formatProviderError(new Error(`Cohere /v2/embed failed: ${response.status} — ${body.slice(0, 500)}`));
|
|
161
|
+
}
|
|
162
|
+
const json = (await response.json());
|
|
163
|
+
const floatVecs = json.embeddings?.float ??
|
|
164
|
+
(Array.isArray(json.embeddings) ? json.embeddings : undefined);
|
|
165
|
+
if (!floatVecs || floatVecs.length !== batch.length) {
|
|
166
|
+
throw new ProviderError(`Cohere /v2/embed returned ${floatVecs?.length ?? 0} embeddings for ${batch.length} inputs.`, "cohere");
|
|
167
|
+
}
|
|
168
|
+
results.push(...floatVecs);
|
|
241
169
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
(Array.isArray(json.embeddings) ? json.embeddings : undefined);
|
|
245
|
-
if (!floatVecs || floatVecs.length !== batch.length) {
|
|
246
|
-
throw new ProviderError(`Cohere /v2/embed returned ${floatVecs?.length ?? 0} embeddings for ${batch.length} inputs.`, "cohere");
|
|
170
|
+
finally {
|
|
171
|
+
timeoutController?.cleanup();
|
|
247
172
|
}
|
|
248
|
-
results.push(...floatVecs);
|
|
249
173
|
}
|
|
250
174
|
return results;
|
|
251
175
|
}
|
|
252
176
|
}
|
|
253
|
-
export default CohereProvider;
|
|
254
177
|
//# sourceMappingURL=cohere.js.map
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DeepSeekModels } from "../constants/enums.js";
|
|
2
2
|
import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../types/index.js";
|
|
3
3
|
import { logger } from "../utils/logger.js";
|
|
4
|
+
import { redactUrlCredentials } from "../utils/logSanitize.js";
|
|
4
5
|
import { createDeepSeekConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
|
|
5
6
|
import { TimeoutError } from "../utils/timeout.js";
|
|
6
7
|
import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
|
|
@@ -55,7 +56,7 @@ export class DeepSeekProvider extends OpenAIChatCompletionsProvider {
|
|
|
55
56
|
logger.debug("DeepSeek Provider initialized", {
|
|
56
57
|
modelName: this.modelName,
|
|
57
58
|
providerName: this.providerName,
|
|
58
|
-
baseURL: this.config.baseURL,
|
|
59
|
+
baseURL: redactUrlCredentials(this.config.baseURL),
|
|
59
60
|
});
|
|
60
61
|
}
|
|
61
62
|
// ===========================================================================
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { FireworksModels } from "../constants/enums.js";
|
|
2
2
|
import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../types/index.js";
|
|
3
3
|
import { logger } from "../utils/logger.js";
|
|
4
|
+
import { redactUrlCredentials } from "../utils/logSanitize.js";
|
|
4
5
|
import { createFireworksConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
|
|
5
6
|
import { TimeoutError } from "../utils/timeout.js";
|
|
6
7
|
import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
|
|
@@ -34,7 +35,7 @@ export class FireworksProvider extends OpenAIChatCompletionsProvider {
|
|
|
34
35
|
logger.debug("Fireworks Provider initialized", {
|
|
35
36
|
modelName: this.modelName,
|
|
36
37
|
providerName: this.providerName,
|
|
37
|
-
baseURL: this.config.baseURL,
|
|
38
|
+
baseURL: redactUrlCredentials(this.config.baseURL),
|
|
38
39
|
});
|
|
39
40
|
}
|
|
40
41
|
getProviderName() {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { GroqModels } from "../constants/enums.js";
|
|
2
2
|
import { AuthenticationError, InvalidModelError, ProviderError, RateLimitError, } from "../types/index.js";
|
|
3
3
|
import { logger } from "../utils/logger.js";
|
|
4
|
+
import { redactUrlCredentials } from "../utils/logSanitize.js";
|
|
4
5
|
import { createGroqConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
|
|
5
6
|
import { TimeoutError } from "../utils/timeout.js";
|
|
6
7
|
import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
|
|
@@ -33,7 +34,7 @@ export class GroqProvider extends OpenAIChatCompletionsProvider {
|
|
|
33
34
|
logger.debug("Groq Provider initialized", {
|
|
34
35
|
modelName: this.modelName,
|
|
35
36
|
providerName: this.providerName,
|
|
36
|
-
baseURL: this.config.baseURL,
|
|
37
|
+
baseURL: redactUrlCredentials(this.config.baseURL),
|
|
37
38
|
});
|
|
38
39
|
}
|
|
39
40
|
getProviderName() {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../types/index.js";
|
|
2
2
|
import { logger } from "../utils/logger.js";
|
|
3
|
+
import { redactUrlCredentials } from "../utils/logSanitize.js";
|
|
3
4
|
import { createHuggingFaceConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
|
|
4
5
|
import { TimeoutError } from "../utils/timeout.js";
|
|
5
6
|
import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
|
|
@@ -33,7 +34,7 @@ export class HuggingFaceProvider extends OpenAIChatCompletionsProvider {
|
|
|
33
34
|
logger.debug("HuggingFaceProvider initialized", {
|
|
34
35
|
modelName: this.modelName,
|
|
35
36
|
providerName: this.providerName,
|
|
36
|
-
baseURL: this.config.baseURL,
|
|
37
|
+
baseURL: redactUrlCredentials(this.config.baseURL),
|
|
37
38
|
});
|
|
38
39
|
}
|
|
39
40
|
getProviderName() {
|
|
@@ -3,6 +3,7 @@ import { createProxyFetch } from "../proxy/proxyFetch.js";
|
|
|
3
3
|
import { AuthenticationError, InvalidModelError, ModelAccessDeniedError, NetworkError, ProviderError, RateLimitError, isModelAccessDeniedMessage, parseAllowedModels, } from "../types/index.js";
|
|
4
4
|
import { isAbortError } from "../utils/errorHandling.js";
|
|
5
5
|
import { logger } from "../utils/logger.js";
|
|
6
|
+
import { redactUrlCredentials } from "../utils/logSanitize.js";
|
|
6
7
|
import { isGemini25Model as isCanonicalGemini25Model } from "../utils/modelDetection.js";
|
|
7
8
|
import { calculateCost } from "../utils/pricing.js";
|
|
8
9
|
import { getProviderModel } from "../utils/providerConfig.js";
|
|
@@ -53,7 +54,7 @@ export class LiteLLMProvider extends OpenAIChatCompletionsProvider {
|
|
|
53
54
|
logger.debug("LiteLLM Provider initialized", {
|
|
54
55
|
modelName: this.modelName,
|
|
55
56
|
provider: this.providerName,
|
|
56
|
-
baseURL: this.config.baseURL,
|
|
57
|
+
baseURL: redactUrlCredentials(this.config.baseURL),
|
|
57
58
|
});
|
|
58
59
|
}
|
|
59
60
|
getProviderName() {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { NetworkError, ProviderError } from "../types/index.js";
|
|
2
2
|
import { logger } from "../utils/logger.js";
|
|
3
|
+
import { redactUrlCredentials } from "../utils/logSanitize.js";
|
|
3
4
|
import { TimeoutError } from "../utils/timeout.js";
|
|
4
5
|
import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
|
|
5
6
|
const LLAMACPP_DEFAULT_BASE_URL = "http://localhost:8080/v1";
|
|
@@ -7,12 +8,6 @@ const LLAMACPP_PLACEHOLDER_KEY = "llamacpp";
|
|
|
7
8
|
const getLlamaCppBaseURL = () => {
|
|
8
9
|
return process.env.LLAMACPP_BASE_URL || LLAMACPP_DEFAULT_BASE_URL;
|
|
9
10
|
};
|
|
10
|
-
/**
|
|
11
|
-
* Strip embedded `user:pass@` credentials from a URL before logging it or
|
|
12
|
-
* surfacing it in a user-facing error. Preserves host/port/path so the URL
|
|
13
|
-
* stays useful for diagnostics.
|
|
14
|
-
*/
|
|
15
|
-
const redactUrlCredentials = (url) => url.replace(/\/\/[^/@]+@/, "//***@");
|
|
16
11
|
/**
|
|
17
12
|
* llama.cpp Provider — direct HTTP, no AI SDK.
|
|
18
13
|
*
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createProxyFetch } from "../proxy/proxyFetch.js";
|
|
2
2
|
import { InvalidModelError, NetworkError, ProviderError, } from "../types/index.js";
|
|
3
3
|
import { logger } from "../utils/logger.js";
|
|
4
|
+
import { redactUrlCredentials } from "../utils/logSanitize.js";
|
|
4
5
|
import { TimeoutError } from "../utils/timeout.js";
|
|
5
6
|
import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
|
|
6
7
|
const LM_STUDIO_DEFAULT_BASE_URL = "http://localhost:1234/v1";
|
|
@@ -34,7 +35,7 @@ export class LMStudioProvider extends OpenAIChatCompletionsProvider {
|
|
|
34
35
|
logger.debug("LM Studio Provider initialized", {
|
|
35
36
|
modelName: this.modelName,
|
|
36
37
|
providerName: this.providerName,
|
|
37
|
-
baseURL: this.config.baseURL,
|
|
38
|
+
baseURL: redactUrlCredentials(this.config.baseURL),
|
|
38
39
|
});
|
|
39
40
|
}
|
|
40
41
|
getProviderName() {
|
|
@@ -60,7 +61,7 @@ export class LMStudioProvider extends OpenAIChatCompletionsProvider {
|
|
|
60
61
|
message.includes("ECONNREFUSED") ||
|
|
61
62
|
message.includes("Failed to fetch") ||
|
|
62
63
|
message.includes("fetch failed")) {
|
|
63
|
-
return new NetworkError(`LM Studio server not reachable at ${this.config.baseURL}. ` +
|
|
64
|
+
return new NetworkError(`LM Studio server not reachable at ${redactUrlCredentials(this.config.baseURL)}. ` +
|
|
64
65
|
`Open the LM Studio app, load a model, and click "Start Server".`, "lm-studio");
|
|
65
66
|
}
|
|
66
67
|
if (message.includes("model_not_found") || message.includes("404")) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { NvidiaNimModels } from "../constants/enums.js";
|
|
2
2
|
import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../types/index.js";
|
|
3
3
|
import { logger } from "../utils/logger.js";
|
|
4
|
+
import { redactUrlCredentials } from "../utils/logSanitize.js";
|
|
4
5
|
import { createNvidiaNimConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
|
|
5
6
|
import { TimeoutError } from "../utils/timeout.js";
|
|
6
7
|
import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
|
|
@@ -164,7 +165,7 @@ export class NvidiaNimProvider extends OpenAIChatCompletionsProvider {
|
|
|
164
165
|
logger.debug("NVIDIA NIM Provider initialized", {
|
|
165
166
|
modelName: this.modelName,
|
|
166
167
|
providerName: this.providerName,
|
|
167
|
-
baseURL: this.config.baseURL,
|
|
168
|
+
baseURL: redactUrlCredentials(this.config.baseURL),
|
|
168
169
|
});
|
|
169
170
|
}
|
|
170
171
|
getProviderName() {
|
|
@@ -3,6 +3,7 @@ import { AIProviderName as AIProviderNameEnum } from "../constants/enums.js";
|
|
|
3
3
|
import { createProxyFetch } from "../proxy/proxyFetch.js";
|
|
4
4
|
import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../types/index.js";
|
|
5
5
|
import { logger } from "../utils/logger.js";
|
|
6
|
+
import { redactUrlCredentials } from "../utils/logSanitize.js";
|
|
6
7
|
import { calculateCost } from "../utils/pricing.js";
|
|
7
8
|
import { createOpenAIConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
|
|
8
9
|
import { MAX_IMAGE_BYTES, readBoundedBuffer } from "../utils/sizeGuard.js";
|
|
@@ -67,7 +68,7 @@ export class OpenAIProvider extends OpenAIChatCompletionsProvider {
|
|
|
67
68
|
logger.debug("OpenAIProvider initialized", {
|
|
68
69
|
model: this.modelName,
|
|
69
70
|
providerName: this.providerName,
|
|
70
|
-
baseURL: this.config.baseURL,
|
|
71
|
+
baseURL: redactUrlCredentials(this.config.baseURL),
|
|
71
72
|
});
|
|
72
73
|
}
|
|
73
74
|
// ===========================================================================
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../types/index.js";
|
|
2
2
|
import { logger } from "../utils/logger.js";
|
|
3
|
+
import { redactUrlCredentials } from "../utils/logSanitize.js";
|
|
3
4
|
import { TimeoutError } from "../utils/timeout.js";
|
|
4
5
|
import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
|
|
5
6
|
const FALLBACK_OPENAI_COMPATIBLE_MODEL = "gpt-3.5-turbo";
|
|
@@ -42,7 +43,7 @@ export class OpenAICompatibleProvider extends OpenAIChatCompletionsProvider {
|
|
|
42
43
|
logger.debug("OpenAI Compatible Provider initialized", {
|
|
43
44
|
modelName: this.modelName,
|
|
44
45
|
provider: this.providerName,
|
|
45
|
-
baseURL: this.config.baseURL,
|
|
46
|
+
baseURL: redactUrlCredentials(this.config.baseURL),
|
|
46
47
|
});
|
|
47
48
|
}
|
|
48
49
|
getProviderName() {
|
|
@@ -78,7 +79,7 @@ export class OpenAICompatibleProvider extends OpenAIChatCompletionsProvider {
|
|
|
78
79
|
if (typeof errorRecord?.message === "string") {
|
|
79
80
|
if (errorRecord.message.includes("ECONNREFUSED") ||
|
|
80
81
|
errorRecord.message.includes("Failed to fetch")) {
|
|
81
|
-
return new NetworkError(`OpenAI Compatible endpoint not available. Please check your OPENAI_COMPATIBLE_BASE_URL: ${this.config.baseURL}`, "openai-compatible");
|
|
82
|
+
return new NetworkError(`OpenAI Compatible endpoint not available. Please check your OPENAI_COMPATIBLE_BASE_URL: ${redactUrlCredentials(this.config.baseURL)}`, "openai-compatible");
|
|
82
83
|
}
|
|
83
84
|
if (errorRecord.message.includes("API_KEY_INVALID") ||
|
|
84
85
|
errorRecord.message.includes("Invalid API key") ||
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { PerplexityModels } from "../constants/enums.js";
|
|
2
2
|
import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../types/index.js";
|
|
3
3
|
import { logger } from "../utils/logger.js";
|
|
4
|
+
import { redactUrlCredentials } from "../utils/logSanitize.js";
|
|
4
5
|
import { createPerplexityConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
|
|
5
6
|
import { TimeoutError } from "../utils/timeout.js";
|
|
6
7
|
import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
|
|
@@ -33,7 +34,7 @@ export class PerplexityProvider extends OpenAIChatCompletionsProvider {
|
|
|
33
34
|
logger.debug("Perplexity Provider initialized", {
|
|
34
35
|
modelName: this.modelName,
|
|
35
36
|
providerName: this.providerName,
|
|
36
|
-
baseURL: this.config.baseURL,
|
|
37
|
+
baseURL: redactUrlCredentials(this.config.baseURL),
|
|
37
38
|
});
|
|
38
39
|
}
|
|
39
40
|
getProviderName() {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { TogetherAIModels } from "../constants/enums.js";
|
|
2
2
|
import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../types/index.js";
|
|
3
3
|
import { logger } from "../utils/logger.js";
|
|
4
|
+
import { redactUrlCredentials } from "../utils/logSanitize.js";
|
|
4
5
|
import { createTogetherAIConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
|
|
5
6
|
import { TimeoutError } from "../utils/timeout.js";
|
|
6
7
|
import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
|
|
@@ -32,7 +33,7 @@ export class TogetherAIProvider extends OpenAIChatCompletionsProvider {
|
|
|
32
33
|
logger.debug("Together AI Provider initialized", {
|
|
33
34
|
modelName: this.modelName,
|
|
34
35
|
providerName: this.providerName,
|
|
35
|
-
baseURL: this.config.baseURL,
|
|
36
|
+
baseURL: redactUrlCredentials(this.config.baseURL),
|
|
36
37
|
});
|
|
37
38
|
}
|
|
38
39
|
getProviderName() {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { XaiModels } from "../constants/enums.js";
|
|
2
2
|
import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../types/index.js";
|
|
3
3
|
import { logger } from "../utils/logger.js";
|
|
4
|
+
import { redactUrlCredentials } from "../utils/logSanitize.js";
|
|
4
5
|
import { createXaiConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
|
|
5
6
|
import { TimeoutError } from "../utils/timeout.js";
|
|
6
7
|
import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
|
|
@@ -34,7 +35,7 @@ export class XaiProvider extends OpenAIChatCompletionsProvider {
|
|
|
34
35
|
logger.debug("xAI Provider initialized", {
|
|
35
36
|
modelName: this.modelName,
|
|
36
37
|
providerName: this.providerName,
|
|
37
|
-
baseURL: this.config.baseURL,
|
|
38
|
+
baseURL: redactUrlCredentials(this.config.baseURL),
|
|
38
39
|
});
|
|
39
40
|
}
|
|
40
41
|
getProviderName() {
|
|
@@ -26,6 +26,20 @@
|
|
|
26
26
|
* @param maxLen - Maximum number of characters to keep (default 500).
|
|
27
27
|
*/
|
|
28
28
|
export declare function sanitizeForLog(text: string, maxLen?: number): string;
|
|
29
|
+
/**
|
|
30
|
+
* Strip embedded `user:pass@` credentials from a URL's authority component
|
|
31
|
+
* before logging it or surfacing it in a user-facing error.
|
|
32
|
+
*
|
|
33
|
+
* Turns `https://user:secret@host/path` into `https://***@host/path` while
|
|
34
|
+
* leaving credential-free URLs untouched, so the host/port/path stay useful
|
|
35
|
+
* for diagnostics. Use this for any `baseURL`/endpoint a caller may have
|
|
36
|
+
* supplied with inline credentials. The match is global, so every `//…@`
|
|
37
|
+
* authority in the string is redacted (e.g. a proxy chain or a URL embedded
|
|
38
|
+
* in a query parameter), not just the first.
|
|
39
|
+
*
|
|
40
|
+
* @param url - The URL (or URL-shaped string) to redact.
|
|
41
|
+
*/
|
|
42
|
+
export declare function redactUrlCredentials(url: string): string;
|
|
29
43
|
/**
|
|
30
44
|
* Recursively sanitize a record/array, returning a structurally identical
|
|
31
45
|
* value with sensitive keys redacted and string values run through
|