@pauly4010/evalai-sdk 1.3.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 +289 -0
- package/LICENSE +21 -0
- package/README.md +565 -0
- package/dist/assertions.d.ts +189 -0
- package/dist/assertions.js +596 -0
- package/dist/batch.d.ts +68 -0
- package/dist/batch.js +178 -0
- package/dist/cache.d.ts +65 -0
- package/dist/cache.js +135 -0
- package/dist/cli/index.d.ts +6 -0
- package/dist/cli/index.js +181 -0
- package/dist/client.d.ts +358 -0
- package/dist/client.js +802 -0
- package/dist/context.d.ts +134 -0
- package/dist/context.js +215 -0
- package/dist/errors.d.ts +80 -0
- package/dist/errors.js +285 -0
- package/dist/export.d.ts +195 -0
- package/dist/export.js +334 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.js +111 -0
- package/dist/integrations/anthropic.d.ts +72 -0
- package/dist/integrations/anthropic.js +159 -0
- package/dist/integrations/openai.d.ts +69 -0
- package/dist/integrations/openai.js +156 -0
- package/dist/local.d.ts +39 -0
- package/dist/local.js +146 -0
- package/dist/logger.d.ts +128 -0
- package/dist/logger.js +227 -0
- package/dist/pagination.d.ts +74 -0
- package/dist/pagination.js +135 -0
- package/dist/snapshot.d.ts +176 -0
- package/dist/snapshot.js +322 -0
- package/dist/streaming.d.ts +173 -0
- package/dist/streaming.js +268 -0
- package/dist/testing.d.ts +204 -0
- package/dist/testing.js +252 -0
- package/dist/types.d.ts +715 -0
- package/dist/types.js +54 -0
- package/dist/workflows.d.ts +378 -0
- package/dist/workflows.js +628 -0
- package/package.json +102 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context Propagation System
|
|
3
|
+
* Tier 2.9: Automatic metadata injection
|
|
4
|
+
*
|
|
5
|
+
* NOTE: In Node.js, uses AsyncLocalStorage for true async context propagation.
|
|
6
|
+
* In browsers, uses a simpler stack-based approach (not safe across async boundaries).
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { createContext } from '@ai-eval-platform/sdk';
|
|
11
|
+
*
|
|
12
|
+
* const context = createContext({ userId: '123', sessionId: 'abc' });
|
|
13
|
+
*
|
|
14
|
+
* await context.run(async () => {
|
|
15
|
+
* // All SDK calls inherit the context
|
|
16
|
+
* await client.traces.create({ name: 'test' });
|
|
17
|
+
* // ^ Automatically includes userId and sessionId
|
|
18
|
+
* });
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Context metadata that will be automatically injected
|
|
23
|
+
*/
|
|
24
|
+
export interface ContextMetadata {
|
|
25
|
+
[key: string]: any;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Context manager for automatic metadata propagation
|
|
29
|
+
*/
|
|
30
|
+
export declare class EvalContext {
|
|
31
|
+
private metadata;
|
|
32
|
+
constructor(metadata: ContextMetadata);
|
|
33
|
+
/**
|
|
34
|
+
* Run a function with this context
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* const context = new EvalContext({ userId: '123' });
|
|
39
|
+
*
|
|
40
|
+
* await context.run(async () => {
|
|
41
|
+
* // All operations inherit context
|
|
42
|
+
* await client.traces.create({ name: 'test' });
|
|
43
|
+
* });
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
run<T>(fn: () => Promise<T>): Promise<T>;
|
|
47
|
+
/**
|
|
48
|
+
* Run a synchronous function with this context
|
|
49
|
+
*/
|
|
50
|
+
runSync<T>(fn: () => T): T;
|
|
51
|
+
/**
|
|
52
|
+
* Get the current context metadata
|
|
53
|
+
*/
|
|
54
|
+
getMetadata(): ContextMetadata;
|
|
55
|
+
/**
|
|
56
|
+
* Merge additional metadata into context
|
|
57
|
+
*/
|
|
58
|
+
with(additionalMetadata: ContextMetadata): EvalContext;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Create a new context with metadata
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```typescript
|
|
65
|
+
* const context = createContext({
|
|
66
|
+
* userId: '123',
|
|
67
|
+
* sessionId: 'abc',
|
|
68
|
+
* environment: 'production'
|
|
69
|
+
* });
|
|
70
|
+
*
|
|
71
|
+
* await context.run(async () => {
|
|
72
|
+
* // All SDK operations inherit context
|
|
73
|
+
* });
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export declare function createContext(metadata: ContextMetadata): EvalContext;
|
|
77
|
+
/**
|
|
78
|
+
* Get the current context metadata (if any)
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* const metadata = getCurrentContext();
|
|
83
|
+
* if (metadata) {
|
|
84
|
+
* console.log(metadata.userId);
|
|
85
|
+
* }
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export declare function getCurrentContext(): ContextMetadata | undefined;
|
|
89
|
+
/**
|
|
90
|
+
* Merge current context with additional metadata
|
|
91
|
+
* Returns combined metadata for use in API calls
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```typescript
|
|
95
|
+
* const params = {
|
|
96
|
+
* name: 'My Trace',
|
|
97
|
+
* metadata: mergeWithContext({ custom: 'value' })
|
|
98
|
+
* };
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
export declare function mergeWithContext(metadata?: Record<string, any>): Record<string, any>;
|
|
102
|
+
/**
|
|
103
|
+
* Run with nested context (merges parent context)
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```typescript
|
|
107
|
+
* await withContext({ userId: '123' }, async () => {
|
|
108
|
+
* await withContext({ requestId: 'req-456' }, async () => {
|
|
109
|
+
* // Has both userId and requestId
|
|
110
|
+
* const ctx = getCurrentContext();
|
|
111
|
+
* console.log(ctx); // { userId: '123', requestId: 'req-456' }
|
|
112
|
+
* });
|
|
113
|
+
* });
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
export declare function withContext<T>(metadata: ContextMetadata, fn: () => Promise<T>): Promise<T>;
|
|
117
|
+
/**
|
|
118
|
+
* Run with nested context (synchronous)
|
|
119
|
+
*/
|
|
120
|
+
export declare function withContextSync<T>(metadata: ContextMetadata, fn: () => T): T;
|
|
121
|
+
/**
|
|
122
|
+
* Decorator for automatic context injection (for class methods)
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```typescript
|
|
126
|
+
* class MyService {
|
|
127
|
+
* @WithContext({ service: 'MyService' })
|
|
128
|
+
* async process() {
|
|
129
|
+
* // Automatically has service context
|
|
130
|
+
* }
|
|
131
|
+
* }
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
export declare function WithContext(metadata: ContextMetadata): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
|
package/dist/context.js
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Context Propagation System
|
|
4
|
+
* Tier 2.9: Automatic metadata injection
|
|
5
|
+
*
|
|
6
|
+
* NOTE: In Node.js, uses AsyncLocalStorage for true async context propagation.
|
|
7
|
+
* In browsers, uses a simpler stack-based approach (not safe across async boundaries).
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { createContext } from '@ai-eval-platform/sdk';
|
|
12
|
+
*
|
|
13
|
+
* const context = createContext({ userId: '123', sessionId: 'abc' });
|
|
14
|
+
*
|
|
15
|
+
* await context.run(async () => {
|
|
16
|
+
* // All SDK calls inherit the context
|
|
17
|
+
* await client.traces.create({ name: 'test' });
|
|
18
|
+
* // ^ Automatically includes userId and sessionId
|
|
19
|
+
* });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.EvalContext = void 0;
|
|
24
|
+
exports.createContext = createContext;
|
|
25
|
+
exports.getCurrentContext = getCurrentContext;
|
|
26
|
+
exports.mergeWithContext = mergeWithContext;
|
|
27
|
+
exports.withContext = withContext;
|
|
28
|
+
exports.withContextSync = withContextSync;
|
|
29
|
+
exports.WithContext = WithContext;
|
|
30
|
+
// Detect environment
|
|
31
|
+
const isNode = typeof process !== 'undefined' &&
|
|
32
|
+
process.versions?.node &&
|
|
33
|
+
typeof require !== 'undefined';
|
|
34
|
+
// Browser fallback: simple context stack
|
|
35
|
+
class BrowserContextStorage {
|
|
36
|
+
constructor() {
|
|
37
|
+
this.stack = [];
|
|
38
|
+
}
|
|
39
|
+
run(context, fn) {
|
|
40
|
+
this.stack.push(context);
|
|
41
|
+
try {
|
|
42
|
+
return fn();
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
this.stack.pop();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
getStore() {
|
|
49
|
+
return this.stack[this.stack.length - 1];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Context storage implementation
|
|
54
|
+
* Uses AsyncLocalStorage in Node.js, simple stack in browsers
|
|
55
|
+
*/
|
|
56
|
+
let contextStorage;
|
|
57
|
+
if (isNode) {
|
|
58
|
+
try {
|
|
59
|
+
// Dynamic import for Node.js only
|
|
60
|
+
const { AsyncLocalStorage } = require('async_hooks');
|
|
61
|
+
// Create without type argument due to require() being untyped
|
|
62
|
+
contextStorage = new AsyncLocalStorage();
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
// Fallback if async_hooks is not available
|
|
66
|
+
contextStorage = new BrowserContextStorage();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
// Use browser storage for non-Node environments
|
|
71
|
+
contextStorage = new BrowserContextStorage();
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Context manager for automatic metadata propagation
|
|
75
|
+
*/
|
|
76
|
+
class EvalContext {
|
|
77
|
+
constructor(metadata) {
|
|
78
|
+
this.metadata = metadata;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Run a function with this context
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```typescript
|
|
85
|
+
* const context = new EvalContext({ userId: '123' });
|
|
86
|
+
*
|
|
87
|
+
* await context.run(async () => {
|
|
88
|
+
* // All operations inherit context
|
|
89
|
+
* await client.traces.create({ name: 'test' });
|
|
90
|
+
* });
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
async run(fn) {
|
|
94
|
+
return contextStorage.run(this.metadata, fn);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Run a synchronous function with this context
|
|
98
|
+
*/
|
|
99
|
+
runSync(fn) {
|
|
100
|
+
return contextStorage.run(this.metadata, fn);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Get the current context metadata
|
|
104
|
+
*/
|
|
105
|
+
getMetadata() {
|
|
106
|
+
return { ...this.metadata };
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Merge additional metadata into context
|
|
110
|
+
*/
|
|
111
|
+
with(additionalMetadata) {
|
|
112
|
+
return new EvalContext({ ...this.metadata, ...additionalMetadata });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
exports.EvalContext = EvalContext;
|
|
116
|
+
/**
|
|
117
|
+
* Create a new context with metadata
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```typescript
|
|
121
|
+
* const context = createContext({
|
|
122
|
+
* userId: '123',
|
|
123
|
+
* sessionId: 'abc',
|
|
124
|
+
* environment: 'production'
|
|
125
|
+
* });
|
|
126
|
+
*
|
|
127
|
+
* await context.run(async () => {
|
|
128
|
+
* // All SDK operations inherit context
|
|
129
|
+
* });
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
function createContext(metadata) {
|
|
133
|
+
return new EvalContext(metadata);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Get the current context metadata (if any)
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```typescript
|
|
140
|
+
* const metadata = getCurrentContext();
|
|
141
|
+
* if (metadata) {
|
|
142
|
+
* console.log(metadata.userId);
|
|
143
|
+
* }
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
function getCurrentContext() {
|
|
147
|
+
return contextStorage.getStore();
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Merge current context with additional metadata
|
|
151
|
+
* Returns combined metadata for use in API calls
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```typescript
|
|
155
|
+
* const params = {
|
|
156
|
+
* name: 'My Trace',
|
|
157
|
+
* metadata: mergeWithContext({ custom: 'value' })
|
|
158
|
+
* };
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
function mergeWithContext(metadata) {
|
|
162
|
+
const current = getCurrentContext();
|
|
163
|
+
if (!current)
|
|
164
|
+
return metadata || {};
|
|
165
|
+
return { ...current, ...metadata };
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Run with nested context (merges parent context)
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* ```typescript
|
|
172
|
+
* await withContext({ userId: '123' }, async () => {
|
|
173
|
+
* await withContext({ requestId: 'req-456' }, async () => {
|
|
174
|
+
* // Has both userId and requestId
|
|
175
|
+
* const ctx = getCurrentContext();
|
|
176
|
+
* console.log(ctx); // { userId: '123', requestId: 'req-456' }
|
|
177
|
+
* });
|
|
178
|
+
* });
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
181
|
+
async function withContext(metadata, fn) {
|
|
182
|
+
const current = getCurrentContext() || {};
|
|
183
|
+
const merged = { ...current, ...metadata };
|
|
184
|
+
return contextStorage.run(merged, fn);
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Run with nested context (synchronous)
|
|
188
|
+
*/
|
|
189
|
+
function withContextSync(metadata, fn) {
|
|
190
|
+
const current = getCurrentContext() || {};
|
|
191
|
+
const merged = { ...current, ...metadata };
|
|
192
|
+
return contextStorage.run(merged, fn);
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Decorator for automatic context injection (for class methods)
|
|
196
|
+
*
|
|
197
|
+
* @example
|
|
198
|
+
* ```typescript
|
|
199
|
+
* class MyService {
|
|
200
|
+
* @WithContext({ service: 'MyService' })
|
|
201
|
+
* async process() {
|
|
202
|
+
* // Automatically has service context
|
|
203
|
+
* }
|
|
204
|
+
* }
|
|
205
|
+
* ```
|
|
206
|
+
*/
|
|
207
|
+
function WithContext(metadata) {
|
|
208
|
+
return function (target, propertyKey, descriptor) {
|
|
209
|
+
const originalMethod = descriptor.value;
|
|
210
|
+
descriptor.value = async function (...args) {
|
|
211
|
+
return withContext(metadata, () => originalMethod.apply(this, args));
|
|
212
|
+
};
|
|
213
|
+
return descriptor;
|
|
214
|
+
};
|
|
215
|
+
}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enhanced SDK Error system with documentation links
|
|
3
|
+
* Tier 1.5: Rich Error Messages
|
|
4
|
+
*/
|
|
5
|
+
export interface ErrorDocumentation {
|
|
6
|
+
code: string;
|
|
7
|
+
message: string;
|
|
8
|
+
documentation: string;
|
|
9
|
+
solutions: string[];
|
|
10
|
+
retryable: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Enhanced SDK Error class with rich error information and documentation
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* try {
|
|
18
|
+
* await client.traces.create({ ... });
|
|
19
|
+
* } catch (error) {
|
|
20
|
+
* if (error instanceof EvalAIError) {
|
|
21
|
+
* console.log(error.code); // 'RATE_LIMIT_EXCEEDED'
|
|
22
|
+
* console.log(error.documentation); // Link to docs
|
|
23
|
+
* console.log(error.solutions); // Array of solutions
|
|
24
|
+
* console.log(error.retryable); // true/false
|
|
25
|
+
*
|
|
26
|
+
* if (error.retryAfter) {
|
|
27
|
+
* console.log(`Retry after ${error.retryAfter} seconds`);
|
|
28
|
+
* }
|
|
29
|
+
* }
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare class EvalAIError extends Error {
|
|
34
|
+
/** Error code for programmatic handling */
|
|
35
|
+
code: string;
|
|
36
|
+
/** HTTP status code */
|
|
37
|
+
statusCode: number;
|
|
38
|
+
/** Link to detailed documentation */
|
|
39
|
+
documentation: string;
|
|
40
|
+
/** Array of suggested solutions */
|
|
41
|
+
solutions: string[];
|
|
42
|
+
/** Whether this error is retryable */
|
|
43
|
+
retryable: boolean;
|
|
44
|
+
/** Additional error details from the API */
|
|
45
|
+
details?: any;
|
|
46
|
+
/** When to retry (for rate limit errors) in seconds */
|
|
47
|
+
retryAfter?: number;
|
|
48
|
+
/** When the limit resets (for feature limit errors) */
|
|
49
|
+
resetAt?: Date;
|
|
50
|
+
constructor(message: string, code: string, statusCode: number, details?: any);
|
|
51
|
+
/**
|
|
52
|
+
* Get formatted error message with solutions
|
|
53
|
+
*/
|
|
54
|
+
getDetailedMessage(): string;
|
|
55
|
+
/**
|
|
56
|
+
* Check if this error should be retried
|
|
57
|
+
*/
|
|
58
|
+
shouldRetry(): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Convert to JSON for logging
|
|
61
|
+
*/
|
|
62
|
+
toJSON(): Record<string, any>;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Create an error from an HTTP response
|
|
66
|
+
*/
|
|
67
|
+
export declare function createErrorFromResponse(response: Response, data: any): EvalAIError;
|
|
68
|
+
export declare class RateLimitError extends EvalAIError {
|
|
69
|
+
constructor(message: string, retryAfter?: number);
|
|
70
|
+
}
|
|
71
|
+
export declare class AuthenticationError extends EvalAIError {
|
|
72
|
+
constructor(message?: string);
|
|
73
|
+
}
|
|
74
|
+
export declare class ValidationError extends EvalAIError {
|
|
75
|
+
constructor(message?: string, details?: any);
|
|
76
|
+
}
|
|
77
|
+
export declare class NetworkError extends EvalAIError {
|
|
78
|
+
constructor(message?: string);
|
|
79
|
+
}
|
|
80
|
+
export { EvalAIError as SDKError };
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Enhanced SDK Error system with documentation links
|
|
4
|
+
* Tier 1.5: Rich Error Messages
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.SDKError = exports.NetworkError = exports.ValidationError = exports.AuthenticationError = exports.RateLimitError = exports.EvalAIError = void 0;
|
|
8
|
+
exports.createErrorFromResponse = createErrorFromResponse;
|
|
9
|
+
/**
|
|
10
|
+
* Comprehensive error documentation
|
|
11
|
+
*/
|
|
12
|
+
const ERROR_DOCS = {
|
|
13
|
+
MISSING_API_KEY: {
|
|
14
|
+
code: 'MISSING_API_KEY',
|
|
15
|
+
message: 'API key is required to initialize the SDK',
|
|
16
|
+
documentation: 'https://docs.ai-eval-platform.com/errors/missing-api-key',
|
|
17
|
+
solutions: [
|
|
18
|
+
'Set EVALAI_API_KEY environment variable',
|
|
19
|
+
'Pass apiKey in config: new AIEvalClient({ apiKey: "..." })',
|
|
20
|
+
'Get your API key from https://platform.ai-eval-platform.com/settings/api-keys'
|
|
21
|
+
],
|
|
22
|
+
retryable: false
|
|
23
|
+
},
|
|
24
|
+
MISSING_ORGANIZATION_ID: {
|
|
25
|
+
code: 'MISSING_ORGANIZATION_ID',
|
|
26
|
+
message: 'Organization ID is required for this operation',
|
|
27
|
+
documentation: 'https://docs.ai-eval-platform.com/errors/missing-org-id',
|
|
28
|
+
solutions: [
|
|
29
|
+
'Set EVALAI_ORGANIZATION_ID environment variable',
|
|
30
|
+
'Pass organizationId in config: new AIEvalClient({ organizationId: 123 })',
|
|
31
|
+
'Pass organizationId in method params'
|
|
32
|
+
],
|
|
33
|
+
retryable: false
|
|
34
|
+
},
|
|
35
|
+
RATE_LIMIT_EXCEEDED: {
|
|
36
|
+
code: 'RATE_LIMIT_EXCEEDED',
|
|
37
|
+
message: 'Rate limit exceeded',
|
|
38
|
+
documentation: 'https://docs.ai-eval-platform.com/errors/rate-limit',
|
|
39
|
+
solutions: [
|
|
40
|
+
'Wait before retrying (check retryAfter property)',
|
|
41
|
+
'Upgrade your plan for higher rate limits',
|
|
42
|
+
'Implement exponential backoff in your application'
|
|
43
|
+
],
|
|
44
|
+
retryable: true
|
|
45
|
+
},
|
|
46
|
+
TIMEOUT: {
|
|
47
|
+
code: 'TIMEOUT',
|
|
48
|
+
message: 'Request timed out',
|
|
49
|
+
documentation: 'https://docs.ai-eval-platform.com/errors/timeout',
|
|
50
|
+
solutions: [
|
|
51
|
+
'Increase timeout: new AIEvalClient({ timeout: 60000 })',
|
|
52
|
+
'Check your network connection',
|
|
53
|
+
'The service may be experiencing high load'
|
|
54
|
+
],
|
|
55
|
+
retryable: true
|
|
56
|
+
},
|
|
57
|
+
NETWORK_ERROR: {
|
|
58
|
+
code: 'NETWORK_ERROR',
|
|
59
|
+
message: 'Network connectivity issue',
|
|
60
|
+
documentation: 'https://docs.ai-eval-platform.com/errors/network',
|
|
61
|
+
solutions: [
|
|
62
|
+
'Check your internet connection',
|
|
63
|
+
'Verify the baseUrl is correct',
|
|
64
|
+
'Check if you can reach the API endpoint'
|
|
65
|
+
],
|
|
66
|
+
retryable: true
|
|
67
|
+
},
|
|
68
|
+
UNAUTHORIZED: {
|
|
69
|
+
code: 'UNAUTHORIZED',
|
|
70
|
+
message: 'Authentication failed',
|
|
71
|
+
documentation: 'https://docs.ai-eval-platform.com/errors/unauthorized',
|
|
72
|
+
solutions: [
|
|
73
|
+
'Verify your API key is correct',
|
|
74
|
+
'Check if your API key has expired',
|
|
75
|
+
'Ensure your API key has the required permissions'
|
|
76
|
+
],
|
|
77
|
+
retryable: false
|
|
78
|
+
},
|
|
79
|
+
FORBIDDEN: {
|
|
80
|
+
code: 'FORBIDDEN',
|
|
81
|
+
message: 'Access forbidden',
|
|
82
|
+
documentation: 'https://docs.ai-eval-platform.com/errors/forbidden',
|
|
83
|
+
solutions: [
|
|
84
|
+
'Check if you have permission for this resource',
|
|
85
|
+
'Verify you\'re using the correct organization ID',
|
|
86
|
+
'Contact support if you believe this is an error'
|
|
87
|
+
],
|
|
88
|
+
retryable: false
|
|
89
|
+
},
|
|
90
|
+
NOT_FOUND: {
|
|
91
|
+
code: 'NOT_FOUND',
|
|
92
|
+
message: 'Resource not found',
|
|
93
|
+
documentation: 'https://docs.ai-eval-platform.com/errors/not-found',
|
|
94
|
+
solutions: [
|
|
95
|
+
'Verify the resource ID is correct',
|
|
96
|
+
'Check if the resource was deleted',
|
|
97
|
+
'Ensure you\'re querying the correct organization'
|
|
98
|
+
],
|
|
99
|
+
retryable: false
|
|
100
|
+
},
|
|
101
|
+
VALIDATION_ERROR: {
|
|
102
|
+
code: 'VALIDATION_ERROR',
|
|
103
|
+
message: 'Request validation failed',
|
|
104
|
+
documentation: 'https://docs.ai-eval-platform.com/errors/validation',
|
|
105
|
+
solutions: [
|
|
106
|
+
'Check the error details for specific validation failures',
|
|
107
|
+
'Verify all required fields are provided',
|
|
108
|
+
'Ensure field types match the expected format'
|
|
109
|
+
],
|
|
110
|
+
retryable: false
|
|
111
|
+
},
|
|
112
|
+
INTERNAL_SERVER_ERROR: {
|
|
113
|
+
code: 'INTERNAL_SERVER_ERROR',
|
|
114
|
+
message: 'Internal server error',
|
|
115
|
+
documentation: 'https://docs.ai-eval-platform.com/errors/server-error',
|
|
116
|
+
solutions: [
|
|
117
|
+
'Retry the request after a brief delay',
|
|
118
|
+
'Check status page: https://status.ai-eval-platform.com',
|
|
119
|
+
'Contact support if the issue persists'
|
|
120
|
+
],
|
|
121
|
+
retryable: true
|
|
122
|
+
},
|
|
123
|
+
FEATURE_LIMIT_REACHED: {
|
|
124
|
+
code: 'FEATURE_LIMIT_REACHED',
|
|
125
|
+
message: 'Feature usage limit reached',
|
|
126
|
+
documentation: 'https://docs.ai-eval-platform.com/errors/feature-limit',
|
|
127
|
+
solutions: [
|
|
128
|
+
'Upgrade your plan for higher limits',
|
|
129
|
+
'Wait for your usage to reset (check resetAt property)',
|
|
130
|
+
'Optimize your usage patterns'
|
|
131
|
+
],
|
|
132
|
+
retryable: false
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* Enhanced SDK Error class with rich error information and documentation
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```typescript
|
|
140
|
+
* try {
|
|
141
|
+
* await client.traces.create({ ... });
|
|
142
|
+
* } catch (error) {
|
|
143
|
+
* if (error instanceof EvalAIError) {
|
|
144
|
+
* console.log(error.code); // 'RATE_LIMIT_EXCEEDED'
|
|
145
|
+
* console.log(error.documentation); // Link to docs
|
|
146
|
+
* console.log(error.solutions); // Array of solutions
|
|
147
|
+
* console.log(error.retryable); // true/false
|
|
148
|
+
*
|
|
149
|
+
* if (error.retryAfter) {
|
|
150
|
+
* console.log(`Retry after ${error.retryAfter} seconds`);
|
|
151
|
+
* }
|
|
152
|
+
* }
|
|
153
|
+
* }
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
class EvalAIError extends Error {
|
|
157
|
+
constructor(message, code, statusCode, details) {
|
|
158
|
+
super(message);
|
|
159
|
+
this.name = 'EvalAIError';
|
|
160
|
+
this.code = code;
|
|
161
|
+
this.statusCode = statusCode;
|
|
162
|
+
this.details = details;
|
|
163
|
+
// Get documentation and solutions
|
|
164
|
+
const errorDoc = ERROR_DOCS[code];
|
|
165
|
+
if (errorDoc) {
|
|
166
|
+
this.documentation = errorDoc.documentation;
|
|
167
|
+
this.solutions = errorDoc.solutions;
|
|
168
|
+
this.retryable = errorDoc.retryable;
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
this.documentation = 'https://docs.ai-eval-platform.com/errors';
|
|
172
|
+
this.solutions = ['Check the API documentation for more information'];
|
|
173
|
+
this.retryable = false;
|
|
174
|
+
}
|
|
175
|
+
// Extract retry-after for rate limits
|
|
176
|
+
if (code === 'RATE_LIMIT_EXCEEDED' && details?.retryAfter) {
|
|
177
|
+
this.retryAfter = details.retryAfter;
|
|
178
|
+
}
|
|
179
|
+
// Extract reset time for feature limits
|
|
180
|
+
if (code === 'FEATURE_LIMIT_REACHED' && details?.resetAt) {
|
|
181
|
+
this.resetAt = new Date(details.resetAt);
|
|
182
|
+
}
|
|
183
|
+
// Ensure proper prototype chain
|
|
184
|
+
Object.setPrototypeOf(this, EvalAIError.prototype);
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Get formatted error message with solutions
|
|
188
|
+
*/
|
|
189
|
+
getDetailedMessage() {
|
|
190
|
+
let msg = `${this.code}: ${this.message}\n\n`;
|
|
191
|
+
msg += `Documentation: ${this.documentation}\n\n`;
|
|
192
|
+
msg += 'Suggested solutions:\n';
|
|
193
|
+
this.solutions.forEach((solution, i) => {
|
|
194
|
+
msg += ` ${i + 1}. ${solution}\n`;
|
|
195
|
+
});
|
|
196
|
+
if (this.retryAfter) {
|
|
197
|
+
msg += `\nRetry after: ${this.retryAfter} seconds`;
|
|
198
|
+
}
|
|
199
|
+
if (this.resetAt) {
|
|
200
|
+
msg += `\nLimit resets at: ${this.resetAt.toISOString()}`;
|
|
201
|
+
}
|
|
202
|
+
return msg;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Check if this error should be retried
|
|
206
|
+
*/
|
|
207
|
+
shouldRetry() {
|
|
208
|
+
return this.retryable;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Convert to JSON for logging
|
|
212
|
+
*/
|
|
213
|
+
toJSON() {
|
|
214
|
+
return {
|
|
215
|
+
name: this.name,
|
|
216
|
+
code: this.code,
|
|
217
|
+
message: this.message,
|
|
218
|
+
statusCode: this.statusCode,
|
|
219
|
+
documentation: this.documentation,
|
|
220
|
+
solutions: this.solutions,
|
|
221
|
+
retryable: this.retryable,
|
|
222
|
+
retryAfter: this.retryAfter,
|
|
223
|
+
resetAt: this.resetAt,
|
|
224
|
+
details: this.details
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
exports.EvalAIError = EvalAIError;
|
|
229
|
+
exports.SDKError = EvalAIError;
|
|
230
|
+
/**
|
|
231
|
+
* Create an error from an HTTP response
|
|
232
|
+
*/
|
|
233
|
+
function createErrorFromResponse(response, data) {
|
|
234
|
+
const status = response.status;
|
|
235
|
+
let code = data?.code || 'UNKNOWN_ERROR';
|
|
236
|
+
let message = data?.error || data?.message || response.statusText;
|
|
237
|
+
// Map HTTP status to error codes
|
|
238
|
+
if (!data?.code) {
|
|
239
|
+
if (status === 401)
|
|
240
|
+
code = 'UNAUTHORIZED';
|
|
241
|
+
else if (status === 403)
|
|
242
|
+
code = 'FORBIDDEN';
|
|
243
|
+
else if (status === 404)
|
|
244
|
+
code = 'NOT_FOUND';
|
|
245
|
+
else if (status === 408)
|
|
246
|
+
code = 'TIMEOUT';
|
|
247
|
+
else if (status === 422)
|
|
248
|
+
code = 'VALIDATION_ERROR';
|
|
249
|
+
else if (status === 429)
|
|
250
|
+
code = 'RATE_LIMIT_EXCEEDED';
|
|
251
|
+
else if (status >= 500)
|
|
252
|
+
code = 'INTERNAL_SERVER_ERROR';
|
|
253
|
+
}
|
|
254
|
+
return new EvalAIError(message, code, status, data);
|
|
255
|
+
}
|
|
256
|
+
// Specific error types
|
|
257
|
+
class RateLimitError extends EvalAIError {
|
|
258
|
+
constructor(message, retryAfter) {
|
|
259
|
+
super(message, 'RATE_LIMIT_EXCEEDED', 429, { retryAfter });
|
|
260
|
+
this.name = 'RateLimitError';
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
exports.RateLimitError = RateLimitError;
|
|
264
|
+
class AuthenticationError extends EvalAIError {
|
|
265
|
+
constructor(message = 'Authentication failed') {
|
|
266
|
+
super(message, 'AUTHENTICATION_ERROR', 401);
|
|
267
|
+
this.name = 'AuthenticationError';
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
exports.AuthenticationError = AuthenticationError;
|
|
271
|
+
class ValidationError extends EvalAIError {
|
|
272
|
+
constructor(message = 'Validation failed', details) {
|
|
273
|
+
super(message, 'VALIDATION_ERROR', 400, details);
|
|
274
|
+
this.name = 'ValidationError';
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
exports.ValidationError = ValidationError;
|
|
278
|
+
class NetworkError extends EvalAIError {
|
|
279
|
+
constructor(message = 'Network request failed') {
|
|
280
|
+
super(message, 'NETWORK_ERROR', 0);
|
|
281
|
+
this.name = 'NetworkError';
|
|
282
|
+
this.retryable = true;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
exports.NetworkError = NetworkError;
|