@juspay/neurolink 7.24.0 → 7.25.0
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/cli/index.js +8 -66
- package/dist/core/baseProvider.d.ts +13 -0
- package/dist/core/baseProvider.js +79 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/lib/core/baseProvider.d.ts +13 -0
- package/dist/lib/core/baseProvider.js +79 -1
- package/dist/lib/index.d.ts +3 -0
- package/dist/lib/index.js +2 -0
- package/dist/lib/middleware/builtin/analytics.d.ts +16 -0
- package/dist/lib/middleware/builtin/analytics.js +130 -0
- package/dist/lib/middleware/factory.d.ts +54 -0
- package/dist/lib/middleware/factory.js +289 -0
- package/dist/lib/middleware/index.d.ts +58 -0
- package/dist/lib/middleware/index.js +67 -0
- package/dist/lib/middleware/registry.d.ts +78 -0
- package/dist/lib/middleware/registry.js +283 -0
- package/dist/lib/middleware/types.d.ts +144 -0
- package/dist/lib/middleware/types.js +1 -0
- package/dist/lib/providers/anthropic.js +25 -33
- package/dist/lib/providers/googleAiStudio.js +10 -11
- package/dist/lib/providers/openAI.js +15 -6
- package/dist/lib/types/errors.d.ts +44 -0
- package/dist/lib/types/errors.js +60 -0
- package/dist/middleware/builtin/analytics.d.ts +16 -0
- package/dist/middleware/builtin/analytics.js +130 -0
- package/dist/middleware/factory.d.ts +54 -0
- package/dist/middleware/factory.js +289 -0
- package/dist/middleware/index.d.ts +58 -0
- package/dist/middleware/index.js +67 -0
- package/dist/middleware/registry.d.ts +78 -0
- package/dist/middleware/registry.js +283 -0
- package/dist/middleware/types.d.ts +144 -0
- package/dist/middleware/types.js +1 -0
- package/dist/providers/anthropic.js +25 -33
- package/dist/providers/googleAiStudio.js +10 -11
- package/dist/providers/openAI.js +15 -6
- package/dist/types/errors.d.ts +44 -0
- package/dist/types/errors.js +60 -0
- package/package.json +1 -1
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { logger } from "../utils/logger.js";
|
|
2
|
+
/**
|
|
3
|
+
* Global middleware registry for NeuroLink
|
|
4
|
+
* Manages registration, configuration, and execution of middleware
|
|
5
|
+
*/
|
|
6
|
+
export class MiddlewareRegistry {
|
|
7
|
+
middleware = new Map();
|
|
8
|
+
globalConfigs = new Map();
|
|
9
|
+
executionStats = new Map();
|
|
10
|
+
/**
|
|
11
|
+
* Register a middleware
|
|
12
|
+
*/
|
|
13
|
+
register(middleware, options = {}) {
|
|
14
|
+
const { replace = false, defaultEnabled = false, globalConfig } = options;
|
|
15
|
+
// Check if middleware already exists
|
|
16
|
+
if (this.middleware.has(middleware.metadata.id) && !replace) {
|
|
17
|
+
throw new Error(`Middleware with ID '${middleware.metadata.id}' already exists. Use replace: true to override.`);
|
|
18
|
+
}
|
|
19
|
+
// Set default enabled state
|
|
20
|
+
if (middleware.metadata.defaultEnabled === undefined) {
|
|
21
|
+
middleware.metadata.defaultEnabled = defaultEnabled;
|
|
22
|
+
}
|
|
23
|
+
// Store middleware
|
|
24
|
+
this.middleware.set(middleware.metadata.id, middleware);
|
|
25
|
+
// Store global configuration if provided
|
|
26
|
+
if (globalConfig) {
|
|
27
|
+
this.globalConfigs.set(middleware.metadata.id, globalConfig);
|
|
28
|
+
}
|
|
29
|
+
logger.debug(`Middleware registered: ${middleware.metadata.id}`, {
|
|
30
|
+
name: middleware.metadata.name,
|
|
31
|
+
priority: middleware.metadata.priority || 0,
|
|
32
|
+
defaultEnabled: middleware.metadata.defaultEnabled,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Unregister a middleware
|
|
37
|
+
*/
|
|
38
|
+
unregister(middlewareId) {
|
|
39
|
+
const removed = this.middleware.delete(middlewareId);
|
|
40
|
+
this.globalConfigs.delete(middlewareId);
|
|
41
|
+
this.executionStats.delete(middlewareId);
|
|
42
|
+
if (removed) {
|
|
43
|
+
logger.debug(`Middleware unregistered: ${middlewareId}`);
|
|
44
|
+
}
|
|
45
|
+
return removed;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Get a registered middleware
|
|
49
|
+
*/
|
|
50
|
+
get(middlewareId) {
|
|
51
|
+
return this.middleware.get(middlewareId);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* List all registered middleware
|
|
55
|
+
*/
|
|
56
|
+
list() {
|
|
57
|
+
return Array.from(this.middleware.values());
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Get middleware IDs sorted by priority
|
|
61
|
+
*/
|
|
62
|
+
getSortedIds() {
|
|
63
|
+
return Array.from(this.middleware.values())
|
|
64
|
+
.sort((a, b) => (b.metadata.priority || 0) - (a.metadata.priority || 0))
|
|
65
|
+
.map((m) => m.metadata.id);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Build middleware chain based on configuration
|
|
69
|
+
*/
|
|
70
|
+
buildChain(context, config = {}) {
|
|
71
|
+
const chain = [];
|
|
72
|
+
const sortedIds = this.getSortedIds();
|
|
73
|
+
for (const middlewareId of sortedIds) {
|
|
74
|
+
const middleware = this.middleware.get(middlewareId);
|
|
75
|
+
if (!middleware) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
const middlewareConfig = config[middlewareId];
|
|
79
|
+
const globalConfig = this.globalConfigs.get(middlewareId);
|
|
80
|
+
// Determine if middleware should be applied
|
|
81
|
+
const shouldApply = this.shouldApplyMiddleware(middleware, middlewareConfig, context);
|
|
82
|
+
if (shouldApply) {
|
|
83
|
+
// Create configured middleware instance
|
|
84
|
+
const configuredMiddleware = this.configureMiddleware(middleware, middlewareConfig, globalConfig, context);
|
|
85
|
+
chain.push(configuredMiddleware);
|
|
86
|
+
logger.debug(`Added middleware to chain: ${middlewareId}`, {
|
|
87
|
+
priority: middleware.metadata.priority || 0,
|
|
88
|
+
chainLength: chain.length,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return chain;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Determine if middleware should be applied based on conditions
|
|
96
|
+
*/
|
|
97
|
+
shouldApplyMiddleware(middleware, config, context) {
|
|
98
|
+
// Check if explicitly disabled
|
|
99
|
+
if (config?.enabled === false) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
// Check if explicitly enabled or default enabled
|
|
103
|
+
const isEnabled = config?.enabled === true ||
|
|
104
|
+
(config?.enabled === undefined && middleware.metadata.defaultEnabled);
|
|
105
|
+
if (!isEnabled) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
// Check conditions
|
|
109
|
+
const conditions = config?.conditions;
|
|
110
|
+
if (!conditions) {
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
// Check provider conditions
|
|
114
|
+
if (conditions.providers &&
|
|
115
|
+
!conditions.providers.includes(context.provider)) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
// Check model conditions
|
|
119
|
+
if (conditions.models && !conditions.models.includes(context.model)) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
// Check option conditions
|
|
123
|
+
if (conditions.options) {
|
|
124
|
+
for (const [key, value] of Object.entries(conditions.options)) {
|
|
125
|
+
if (context.options[key] !== value) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// Check custom condition
|
|
131
|
+
if (conditions.custom && !conditions.custom(context)) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Configure middleware with runtime configuration
|
|
138
|
+
*/
|
|
139
|
+
configureMiddleware(middleware, config, globalConfig, context) {
|
|
140
|
+
// Merge configurations: global < middleware config < runtime config
|
|
141
|
+
const mergedConfig = {
|
|
142
|
+
...globalConfig,
|
|
143
|
+
...config?.config,
|
|
144
|
+
};
|
|
145
|
+
// Create wrapper that tracks execution
|
|
146
|
+
const wrappedMiddleware = {};
|
|
147
|
+
if (middleware.transformParams) {
|
|
148
|
+
wrappedMiddleware.transformParams = async (args) => {
|
|
149
|
+
const startTime = Date.now();
|
|
150
|
+
try {
|
|
151
|
+
const result = await middleware.transformParams(args);
|
|
152
|
+
this.recordExecution(middleware.metadata.id, startTime, true);
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
this.recordExecution(middleware.metadata.id, startTime, false, error);
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
if (middleware.wrapGenerate) {
|
|
162
|
+
wrappedMiddleware.wrapGenerate = async (args) => {
|
|
163
|
+
const startTime = Date.now();
|
|
164
|
+
try {
|
|
165
|
+
const result = await middleware.wrapGenerate(args);
|
|
166
|
+
this.recordExecution(middleware.metadata.id, startTime, true);
|
|
167
|
+
return result;
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
this.recordExecution(middleware.metadata.id, startTime, false, error);
|
|
171
|
+
throw error;
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
if (middleware.wrapStream) {
|
|
176
|
+
wrappedMiddleware.wrapStream = async (args) => {
|
|
177
|
+
const startTime = Date.now();
|
|
178
|
+
try {
|
|
179
|
+
const result = await middleware.wrapStream(args);
|
|
180
|
+
this.recordExecution(middleware.metadata.id, startTime, true);
|
|
181
|
+
return result;
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
this.recordExecution(middleware.metadata.id, startTime, false, error);
|
|
185
|
+
throw error;
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
return wrappedMiddleware;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Record middleware execution statistics
|
|
193
|
+
*/
|
|
194
|
+
recordExecution(middlewareId, startTime, success, error) {
|
|
195
|
+
const executionTime = Date.now() - startTime;
|
|
196
|
+
const result = {
|
|
197
|
+
applied: true,
|
|
198
|
+
executionTime,
|
|
199
|
+
error,
|
|
200
|
+
};
|
|
201
|
+
if (!this.executionStats.has(middlewareId)) {
|
|
202
|
+
this.executionStats.set(middlewareId, []);
|
|
203
|
+
}
|
|
204
|
+
const stats = this.executionStats.get(middlewareId) || [];
|
|
205
|
+
stats.push(result);
|
|
206
|
+
// Keep only last 100 executions per middleware
|
|
207
|
+
if (stats.length > 100) {
|
|
208
|
+
stats.shift();
|
|
209
|
+
}
|
|
210
|
+
if (error) {
|
|
211
|
+
logger.warn(`Middleware execution failed: ${middlewareId}`, {
|
|
212
|
+
executionTime,
|
|
213
|
+
error: error.message,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
logger.debug(`Middleware executed: ${middlewareId}`, {
|
|
218
|
+
executionTime,
|
|
219
|
+
success,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Get execution statistics for a middleware
|
|
225
|
+
*/
|
|
226
|
+
getExecutionStats(middlewareId) {
|
|
227
|
+
return this.executionStats.get(middlewareId) || [];
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Get aggregated statistics for all middleware
|
|
231
|
+
*/
|
|
232
|
+
getAggregatedStats() {
|
|
233
|
+
const stats = {};
|
|
234
|
+
for (const [middlewareId, executions] of this.executionStats.entries()) {
|
|
235
|
+
const successful = executions.filter((e) => !e.error).length;
|
|
236
|
+
const failed = executions.filter((e) => e.error).length;
|
|
237
|
+
const totalTime = executions.reduce((sum, e) => sum + e.executionTime, 0);
|
|
238
|
+
const lastExecution = executions[executions.length - 1];
|
|
239
|
+
stats[middlewareId] = {
|
|
240
|
+
totalExecutions: executions.length,
|
|
241
|
+
successfulExecutions: successful,
|
|
242
|
+
failedExecutions: failed,
|
|
243
|
+
averageExecutionTime: executions.length > 0 ? totalTime / executions.length : 0,
|
|
244
|
+
lastExecutionTime: lastExecution?.executionTime || 0,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
return stats;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Clear execution statistics
|
|
251
|
+
*/
|
|
252
|
+
clearStats(middlewareId) {
|
|
253
|
+
if (middlewareId) {
|
|
254
|
+
this.executionStats.delete(middlewareId);
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
this.executionStats.clear();
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Check if a middleware is registered
|
|
262
|
+
*/
|
|
263
|
+
has(middlewareId) {
|
|
264
|
+
return this.middleware.has(middlewareId);
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Get the number of registered middleware
|
|
268
|
+
*/
|
|
269
|
+
size() {
|
|
270
|
+
return this.middleware.size;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Clear all registered middleware
|
|
274
|
+
*/
|
|
275
|
+
clear() {
|
|
276
|
+
this.middleware.clear();
|
|
277
|
+
this.globalConfigs.clear();
|
|
278
|
+
this.executionStats.clear();
|
|
279
|
+
logger.debug("All middleware cleared from registry");
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
// Global middleware registry instance
|
|
283
|
+
export const middlewareRegistry = new MiddlewareRegistry();
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import type { LanguageModelV1Middleware } from "ai";
|
|
2
|
+
import type { JsonValue } from "../types/common.js";
|
|
3
|
+
/**
|
|
4
|
+
* Metadata interface for NeuroLink middleware
|
|
5
|
+
* Provides additional information about middleware without affecting execution
|
|
6
|
+
*/
|
|
7
|
+
export interface NeuroLinkMiddlewareMetadata {
|
|
8
|
+
/** Unique identifier for the middleware */
|
|
9
|
+
id: string;
|
|
10
|
+
/** Human-readable name */
|
|
11
|
+
name: string;
|
|
12
|
+
/** Description of what the middleware does */
|
|
13
|
+
description?: string;
|
|
14
|
+
/** Priority for ordering (higher = earlier in chain) */
|
|
15
|
+
priority?: number;
|
|
16
|
+
/** Whether this middleware is enabled by default */
|
|
17
|
+
defaultEnabled?: boolean;
|
|
18
|
+
/** Configuration schema for the middleware */
|
|
19
|
+
configSchema?: Record<string, unknown>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* NeuroLink middleware with metadata
|
|
23
|
+
* Combines standard AI SDK middleware with NeuroLink-specific metadata
|
|
24
|
+
*/
|
|
25
|
+
export interface NeuroLinkMiddleware extends LanguageModelV1Middleware {
|
|
26
|
+
/** Middleware metadata */
|
|
27
|
+
readonly metadata: NeuroLinkMiddlewareMetadata;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Middleware configuration options
|
|
31
|
+
*/
|
|
32
|
+
export interface MiddlewareConfig {
|
|
33
|
+
/** Whether the middleware is enabled */
|
|
34
|
+
enabled?: boolean;
|
|
35
|
+
/** Middleware-specific configuration */
|
|
36
|
+
config?: Record<string, JsonValue>;
|
|
37
|
+
/** Conditions under which to apply this middleware */
|
|
38
|
+
conditions?: MiddlewareConditions;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Conditions for applying middleware
|
|
42
|
+
*/
|
|
43
|
+
export interface MiddlewareConditions {
|
|
44
|
+
/** Apply only to specific providers */
|
|
45
|
+
providers?: string[];
|
|
46
|
+
/** Apply only to specific models */
|
|
47
|
+
models?: string[];
|
|
48
|
+
/** Apply only when certain options are present */
|
|
49
|
+
options?: Record<string, unknown>;
|
|
50
|
+
/** Custom condition function */
|
|
51
|
+
custom?: (context: MiddlewareContext) => boolean;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Context passed to middleware for decision making
|
|
55
|
+
*/
|
|
56
|
+
export interface MiddlewareContext {
|
|
57
|
+
/** Provider name */
|
|
58
|
+
provider: string;
|
|
59
|
+
/** Model name */
|
|
60
|
+
model: string;
|
|
61
|
+
/** Request options */
|
|
62
|
+
options: Record<string, unknown>;
|
|
63
|
+
/** Session information */
|
|
64
|
+
session?: {
|
|
65
|
+
sessionId?: string;
|
|
66
|
+
userId?: string;
|
|
67
|
+
};
|
|
68
|
+
/** Additional metadata */
|
|
69
|
+
metadata?: Record<string, JsonValue>;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Middleware registration options
|
|
73
|
+
*/
|
|
74
|
+
export interface MiddlewareRegistrationOptions {
|
|
75
|
+
/** Whether to replace existing middleware with same ID */
|
|
76
|
+
replace?: boolean;
|
|
77
|
+
/** Whether to enable the middleware by default */
|
|
78
|
+
defaultEnabled?: boolean;
|
|
79
|
+
/** Global configuration for the middleware */
|
|
80
|
+
globalConfig?: Record<string, JsonValue>;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Middleware execution result
|
|
84
|
+
*/
|
|
85
|
+
export interface MiddlewareExecutionResult {
|
|
86
|
+
/** Whether the middleware was applied */
|
|
87
|
+
applied: boolean;
|
|
88
|
+
/** Execution time in milliseconds */
|
|
89
|
+
executionTime: number;
|
|
90
|
+
/** Any errors that occurred */
|
|
91
|
+
error?: Error;
|
|
92
|
+
/** Additional metadata from the middleware */
|
|
93
|
+
metadata?: Record<string, JsonValue>;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Middleware chain execution statistics
|
|
97
|
+
*/
|
|
98
|
+
export interface MiddlewareChainStats {
|
|
99
|
+
/** Total number of middleware in the chain */
|
|
100
|
+
totalMiddleware: number;
|
|
101
|
+
/** Number of middleware that were applied */
|
|
102
|
+
appliedMiddleware: number;
|
|
103
|
+
/** Total execution time for the chain */
|
|
104
|
+
totalExecutionTime: number;
|
|
105
|
+
/** Individual middleware execution results */
|
|
106
|
+
results: Record<string, MiddlewareExecutionResult>;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Built-in middleware types
|
|
110
|
+
*/
|
|
111
|
+
export type BuiltInMiddlewareType = "analytics" | "guardrails" | "logging" | "caching" | "rateLimit" | "retry" | "timeout";
|
|
112
|
+
/**
|
|
113
|
+
* Middleware preset configurations
|
|
114
|
+
*/
|
|
115
|
+
export interface MiddlewarePreset {
|
|
116
|
+
/** Preset name */
|
|
117
|
+
name: string;
|
|
118
|
+
/** Description of the preset */
|
|
119
|
+
description: string;
|
|
120
|
+
/** Middleware configurations in the preset */
|
|
121
|
+
middleware: Record<string, MiddlewareConfig>;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Factory options for middleware
|
|
125
|
+
*/
|
|
126
|
+
export interface MiddlewareFactoryOptions {
|
|
127
|
+
/** Enable specific middleware */
|
|
128
|
+
enabledMiddleware?: string[];
|
|
129
|
+
/** Disable specific middleware */
|
|
130
|
+
disabledMiddleware?: string[];
|
|
131
|
+
/** Middleware configurations */
|
|
132
|
+
middlewareConfig?: Record<string, MiddlewareConfig>;
|
|
133
|
+
/** Use a preset configuration */
|
|
134
|
+
preset?: string;
|
|
135
|
+
/** Global middleware settings */
|
|
136
|
+
global?: {
|
|
137
|
+
/** Maximum execution time for middleware chain */
|
|
138
|
+
maxExecutionTime?: number;
|
|
139
|
+
/** Whether to continue on middleware errors */
|
|
140
|
+
continueOnError?: boolean;
|
|
141
|
+
/** Whether to collect execution statistics */
|
|
142
|
+
collectStats?: boolean;
|
|
143
|
+
};
|
|
144
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -3,6 +3,7 @@ import { streamText } from "ai";
|
|
|
3
3
|
import { BaseProvider } from "../core/baseProvider.js";
|
|
4
4
|
import { logger } from "../utils/logger.js";
|
|
5
5
|
import { createTimeoutController, TimeoutError, } from "../utils/timeout.js";
|
|
6
|
+
import { AuthenticationError, NetworkError, ProviderError, RateLimitError, } from "../types/errors.js";
|
|
6
7
|
import { DEFAULT_MAX_TOKENS, DEFAULT_MAX_STEPS } from "../core/constants.js";
|
|
7
8
|
import { validateApiKey, createAnthropicConfig, getProviderModel, } from "../utils/providerConfig.js";
|
|
8
9
|
import { buildMessagesArray } from "../utils/messageBuilder.js";
|
|
@@ -50,45 +51,36 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
50
51
|
}
|
|
51
52
|
handleProviderError(error) {
|
|
52
53
|
if (error instanceof TimeoutError) {
|
|
53
|
-
|
|
54
|
+
throw new NetworkError(`Request timed out after ${error.timeout}ms`, this.providerName);
|
|
54
55
|
}
|
|
55
56
|
const errorRecord = error;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
const message = typeof errorRecord?.message === "string"
|
|
58
|
+
? errorRecord.message
|
|
59
|
+
: "Unknown error";
|
|
60
|
+
if (message.includes("API_KEY_INVALID") ||
|
|
61
|
+
message.includes("Invalid API key")) {
|
|
62
|
+
throw new AuthenticationError("Invalid Anthropic API key. Please check your ANTHROPIC_API_KEY environment variable.", this.providerName);
|
|
62
63
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
errorRecord.message.includes("429"))) {
|
|
68
|
-
return new Error("Anthropic rate limit exceeded. Please try again later.");
|
|
64
|
+
if (message.includes("rate limit") ||
|
|
65
|
+
message.includes("too_many_requests") ||
|
|
66
|
+
message.includes("429")) {
|
|
67
|
+
throw new RateLimitError("Anthropic rate limit exceeded. Please try again later.", this.providerName);
|
|
69
68
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
errorRecord.message.includes("connection"))) {
|
|
77
|
-
return new Error("Anthropic API connection error. Please check your internet connection and try again.");
|
|
69
|
+
if (message.includes("ECONNRESET") ||
|
|
70
|
+
message.includes("ENOTFOUND") ||
|
|
71
|
+
message.includes("ECONNREFUSED") ||
|
|
72
|
+
message.includes("network") ||
|
|
73
|
+
message.includes("connection")) {
|
|
74
|
+
throw new NetworkError(`Connection error: ${message}`, this.providerName);
|
|
78
75
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
errorRecord.message.includes("server error"))) {
|
|
86
|
-
return new Error("Anthropic API server error. Please try again in a few moments.");
|
|
76
|
+
if (message.includes("500") ||
|
|
77
|
+
message.includes("502") ||
|
|
78
|
+
message.includes("503") ||
|
|
79
|
+
message.includes("504") ||
|
|
80
|
+
message.includes("server error")) {
|
|
81
|
+
throw new ProviderError(`Server error: ${message}`, this.providerName);
|
|
87
82
|
}
|
|
88
|
-
|
|
89
|
-
? errorRecord.message
|
|
90
|
-
: "Unknown error";
|
|
91
|
-
return new Error(`Anthropic error: ${message}`);
|
|
83
|
+
throw new ProviderError(`Anthropic error: ${message}`, this.providerName);
|
|
92
84
|
}
|
|
93
85
|
// executeGenerate removed - BaseProvider handles all generation with tools
|
|
94
86
|
async executeStream(options, analysisSchema) {
|
|
@@ -4,6 +4,7 @@ import { GoogleAIModels } from "../core/types.js";
|
|
|
4
4
|
import { BaseProvider } from "../core/baseProvider.js";
|
|
5
5
|
import { logger } from "../utils/logger.js";
|
|
6
6
|
import { createTimeoutController, TimeoutError, } from "../utils/timeout.js";
|
|
7
|
+
import { AuthenticationError, NetworkError, ProviderError, RateLimitError, } from "../types/errors.js";
|
|
7
8
|
import { DEFAULT_MAX_TOKENS, DEFAULT_MAX_STEPS } from "../core/constants.js";
|
|
8
9
|
import { streamAnalyticsCollector } from "../core/streamAnalytics.js";
|
|
9
10
|
import { buildMessagesArray } from "../utils/messageBuilder.js";
|
|
@@ -44,21 +45,19 @@ export class GoogleAIStudioProvider extends BaseProvider {
|
|
|
44
45
|
}
|
|
45
46
|
handleProviderError(error) {
|
|
46
47
|
if (error instanceof TimeoutError) {
|
|
47
|
-
|
|
48
|
+
throw new NetworkError(error.message, this.providerName);
|
|
48
49
|
}
|
|
49
50
|
const errorRecord = error;
|
|
50
|
-
if (typeof errorRecord?.message === "string" &&
|
|
51
|
-
errorRecord.message.includes("API_KEY_INVALID")) {
|
|
52
|
-
return new Error("Invalid Google AI API key. Please check your GOOGLE_AI_API_KEY environment variable.");
|
|
53
|
-
}
|
|
54
|
-
if (typeof errorRecord?.message === "string" &&
|
|
55
|
-
errorRecord.message.includes("RATE_LIMIT_EXCEEDED")) {
|
|
56
|
-
return new Error("Google AI rate limit exceeded. Please try again later.");
|
|
57
|
-
}
|
|
58
51
|
const message = typeof errorRecord?.message === "string"
|
|
59
52
|
? errorRecord.message
|
|
60
53
|
: "Unknown error";
|
|
61
|
-
|
|
54
|
+
if (message.includes("API_KEY_INVALID")) {
|
|
55
|
+
throw new AuthenticationError("Invalid Google AI API key. Please check your GOOGLE_AI_API_KEY environment variable.", this.providerName);
|
|
56
|
+
}
|
|
57
|
+
if (message.includes("RATE_LIMIT_EXCEEDED")) {
|
|
58
|
+
throw new RateLimitError("Google AI rate limit exceeded. Please try again later.", this.providerName);
|
|
59
|
+
}
|
|
60
|
+
throw new ProviderError(`Google AI error: ${message}`, this.providerName);
|
|
62
61
|
}
|
|
63
62
|
// executeGenerate removed - BaseProvider handles all generation with tools
|
|
64
63
|
async executeStream(options, analysisSchema) {
|
|
@@ -119,7 +118,7 @@ export class GoogleAIStudioProvider extends BaseProvider {
|
|
|
119
118
|
getApiKey() {
|
|
120
119
|
const apiKey = process.env.GOOGLE_AI_API_KEY || process.env.GOOGLE_GENERATIVE_AI_API_KEY;
|
|
121
120
|
if (!apiKey) {
|
|
122
|
-
throw new
|
|
121
|
+
throw new AuthenticationError("GOOGLE_AI_API_KEY or GOOGLE_GENERATIVE_AI_API_KEY environment variable is not set", this.providerName);
|
|
123
122
|
}
|
|
124
123
|
return apiKey;
|
|
125
124
|
}
|
|
@@ -4,6 +4,7 @@ import { AIProviderName } from "../core/types.js";
|
|
|
4
4
|
import { BaseProvider } from "../core/baseProvider.js";
|
|
5
5
|
import { logger } from "../utils/logger.js";
|
|
6
6
|
import { createTimeoutController, TimeoutError, } from "../utils/timeout.js";
|
|
7
|
+
import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../types/errors.js";
|
|
7
8
|
import { DEFAULT_MAX_TOKENS, DEFAULT_MAX_STEPS } from "../core/constants.js";
|
|
8
9
|
import { validateApiKey, createOpenAIConfig, getProviderModel, } from "../utils/providerConfig.js";
|
|
9
10
|
import { streamAnalyticsCollector } from "../core/streamAnalytics.js";
|
|
@@ -53,20 +54,28 @@ export class OpenAIProvider extends BaseProvider {
|
|
|
53
54
|
}
|
|
54
55
|
handleProviderError(error) {
|
|
55
56
|
if (error instanceof TimeoutError) {
|
|
56
|
-
|
|
57
|
+
throw new NetworkError(error.message, this.providerName);
|
|
57
58
|
}
|
|
58
59
|
const errorObj = error;
|
|
59
60
|
const message = errorObj?.message && typeof errorObj.message === "string"
|
|
60
61
|
? errorObj.message
|
|
61
62
|
: "Unknown error";
|
|
63
|
+
const errorType = errorObj?.type && typeof errorObj.type === "string"
|
|
64
|
+
? errorObj.type
|
|
65
|
+
: undefined;
|
|
62
66
|
if (message.includes("API_KEY_INVALID") ||
|
|
63
|
-
message.includes("Invalid API key")
|
|
64
|
-
|
|
67
|
+
message.includes("Invalid API key") ||
|
|
68
|
+
errorType === "invalid_api_key") {
|
|
69
|
+
throw new AuthenticationError("Invalid OpenAI API key. Please check your OPENAI_API_KEY environment variable.", this.providerName);
|
|
65
70
|
}
|
|
66
|
-
if (message.includes("rate limit")) {
|
|
67
|
-
|
|
71
|
+
if (message.includes("rate limit") || errorType === "rate_limit_error") {
|
|
72
|
+
throw new RateLimitError("OpenAI rate limit exceeded. Please try again later.", this.providerName);
|
|
68
73
|
}
|
|
69
|
-
|
|
74
|
+
if (message.includes("model_not_found")) {
|
|
75
|
+
throw new InvalidModelError(`Model not found: ${this.modelName}`, this.providerName);
|
|
76
|
+
}
|
|
77
|
+
// Generic provider error
|
|
78
|
+
throw new ProviderError(`OpenAI error: ${message}`, this.providerName);
|
|
70
79
|
}
|
|
71
80
|
/**
|
|
72
81
|
* executeGenerate method removed - generation is now handled by BaseProvider.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base error class for all NeuroLink-specific errors.
|
|
3
|
+
* This allows for easy identification of errors thrown by the SDK.
|
|
4
|
+
*/
|
|
5
|
+
export declare class BaseError extends Error {
|
|
6
|
+
constructor(message: string);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Thrown when a provider encounters a generic error.
|
|
10
|
+
*/
|
|
11
|
+
export declare class ProviderError extends BaseError {
|
|
12
|
+
provider?: string | undefined;
|
|
13
|
+
constructor(message: string, provider?: string | undefined);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Thrown for authentication-related errors, such as invalid or missing API keys.
|
|
17
|
+
*/
|
|
18
|
+
export declare class AuthenticationError extends ProviderError {
|
|
19
|
+
constructor(message: string, provider?: string);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Thrown for authorization errors, where the user does not have permission.
|
|
23
|
+
*/
|
|
24
|
+
export declare class AuthorizationError extends ProviderError {
|
|
25
|
+
constructor(message: string, provider?: string);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Thrown for network-related issues, such as connectivity problems or timeouts.
|
|
29
|
+
*/
|
|
30
|
+
export declare class NetworkError extends ProviderError {
|
|
31
|
+
constructor(message: string, provider?: string);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Thrown when an API rate limit has been exceeded.
|
|
35
|
+
*/
|
|
36
|
+
export declare class RateLimitError extends ProviderError {
|
|
37
|
+
constructor(message: string, provider?: string);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Thrown when a specified model is not found or is invalid for the provider.
|
|
41
|
+
*/
|
|
42
|
+
export declare class InvalidModelError extends ProviderError {
|
|
43
|
+
constructor(message: string, provider?: string);
|
|
44
|
+
}
|