@pauly4010/evalai-sdk 1.4.1 → 1.5.5
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 +85 -0
- package/README.md +205 -543
- package/dist/assertions.d.ts +2 -2
- package/dist/assertions.js +104 -71
- package/dist/batch.js +12 -17
- package/dist/cache.js +7 -11
- package/dist/cli/api.d.ts +108 -0
- package/dist/cli/api.js +130 -0
- package/dist/cli/check.d.ts +28 -13
- package/dist/cli/check.js +249 -142
- package/dist/cli/ci-context.d.ts +6 -0
- package/dist/cli/ci-context.js +110 -0
- package/dist/cli/config.d.ts +30 -0
- package/dist/cli/config.js +207 -0
- package/dist/cli/constants.d.ts +15 -0
- package/dist/cli/constants.js +18 -0
- package/dist/cli/doctor.d.ts +11 -0
- package/dist/cli/doctor.js +82 -0
- package/dist/cli/formatters/github.d.ts +8 -0
- package/dist/cli/formatters/github.js +130 -0
- package/dist/cli/formatters/human.d.ts +6 -0
- package/dist/cli/formatters/human.js +107 -0
- package/dist/cli/formatters/json.d.ts +6 -0
- package/dist/cli/formatters/json.js +10 -0
- package/dist/cli/formatters/pr-comment.d.ts +12 -0
- package/dist/cli/formatters/pr-comment.js +101 -0
- package/dist/cli/formatters/types.d.ts +100 -0
- package/dist/cli/formatters/types.js +5 -0
- package/dist/cli/gate.d.ts +21 -0
- package/dist/cli/gate.js +175 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +67 -23
- package/dist/cli/init.d.ts +7 -0
- package/dist/cli/init.js +69 -0
- package/dist/cli/policy-packs.d.ts +23 -0
- package/dist/cli/policy-packs.js +83 -0
- package/dist/cli/profiles.d.ts +28 -0
- package/dist/cli/profiles.js +30 -0
- package/dist/cli/reason-codes.d.ts +17 -0
- package/dist/cli/reason-codes.js +19 -0
- package/dist/cli/render/snippet.d.ts +5 -0
- package/dist/cli/render/snippet.js +15 -0
- package/dist/cli/render/sort.d.ts +10 -0
- package/dist/cli/render/sort.js +24 -0
- package/dist/cli/report/build-check-report.d.ts +19 -0
- package/dist/cli/report/build-check-report.js +124 -0
- package/dist/cli/share.d.ts +17 -0
- package/dist/cli/share.js +83 -0
- package/dist/client.d.ts +2 -2
- package/dist/client.js +144 -132
- package/dist/context.d.ts +1 -1
- package/dist/context.js +4 -6
- package/dist/errors.d.ts +2 -0
- package/dist/errors.js +116 -107
- package/dist/export.d.ts +6 -6
- package/dist/export.js +39 -33
- package/dist/index.d.ts +25 -24
- package/dist/index.js +62 -56
- package/dist/integrations/anthropic.d.ts +1 -1
- package/dist/integrations/anthropic.js +23 -19
- package/dist/integrations/openai-eval.d.ts +57 -0
- package/dist/integrations/openai-eval.js +230 -0
- package/dist/integrations/openai.d.ts +1 -1
- package/dist/integrations/openai.js +23 -19
- package/dist/local.d.ts +2 -2
- package/dist/local.js +25 -25
- package/dist/logger.d.ts +1 -1
- package/dist/logger.js +24 -28
- package/dist/matchers/index.d.ts +1 -0
- package/dist/matchers/index.js +6 -0
- package/dist/matchers/to-pass-gate.d.ts +29 -0
- package/dist/matchers/to-pass-gate.js +35 -0
- package/dist/pagination.d.ts +1 -1
- package/dist/pagination.js +6 -6
- package/dist/snapshot.js +24 -24
- package/dist/streaming.js +11 -11
- package/dist/testing.d.ts +6 -2
- package/dist/testing.js +30 -12
- package/dist/types.d.ts +22 -22
- package/dist/types.js +13 -13
- package/dist/utils/input-hash.d.ts +8 -0
- package/dist/utils/input-hash.js +38 -0
- package/dist/version.d.ts +7 -0
- package/dist/version.js +10 -0
- package/dist/workflows.d.ts +7 -7
- package/dist/workflows.js +44 -44
- package/package.json +102 -90
- package/dist/__tests__/assertions.test.d.ts +0 -1
- package/dist/__tests__/assertions.test.js +0 -288
- package/dist/__tests__/client.test.d.ts +0 -1
- package/dist/__tests__/client.test.js +0 -185
- package/dist/__tests__/testing.test.d.ts +0 -1
- package/dist/__tests__/testing.test.js +0 -230
- package/dist/__tests__/workflows.test.d.ts +0 -1
- package/dist/__tests__/workflows.test.js +0 -222
package/dist/context.d.ts
CHANGED
|
@@ -131,4 +131,4 @@ export declare function withContextSync<T>(metadata: ContextMetadata, fn: () =>
|
|
|
131
131
|
* }
|
|
132
132
|
* ```
|
|
133
133
|
*/
|
|
134
|
-
export declare function WithContext(metadata: ContextMetadata): (
|
|
134
|
+
export declare function WithContext(metadata: ContextMetadata): (_target: any, _propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
|
package/dist/context.js
CHANGED
|
@@ -28,9 +28,7 @@ exports.withContext = withContext;
|
|
|
28
28
|
exports.withContextSync = withContextSync;
|
|
29
29
|
exports.WithContext = WithContext;
|
|
30
30
|
// Detect environment
|
|
31
|
-
const isNode = typeof process !==
|
|
32
|
-
process.versions?.node &&
|
|
33
|
-
typeof require !== 'undefined';
|
|
31
|
+
const isNode = typeof process !== "undefined" && process.versions?.node && typeof require !== "undefined";
|
|
34
32
|
// Browser fallback: simple context stack
|
|
35
33
|
class BrowserContextStorage {
|
|
36
34
|
constructor() {
|
|
@@ -57,11 +55,11 @@ let contextStorage;
|
|
|
57
55
|
if (isNode) {
|
|
58
56
|
try {
|
|
59
57
|
// Dynamic import for Node.js only
|
|
60
|
-
const { AsyncLocalStorage } = require(
|
|
58
|
+
const { AsyncLocalStorage } = require("node:async_hooks");
|
|
61
59
|
// Create without type argument due to require() being untyped
|
|
62
60
|
contextStorage = new AsyncLocalStorage();
|
|
63
61
|
}
|
|
64
|
-
catch (
|
|
62
|
+
catch (_error) {
|
|
65
63
|
// Fallback if async_hooks is not available
|
|
66
64
|
contextStorage = new BrowserContextStorage();
|
|
67
65
|
}
|
|
@@ -205,7 +203,7 @@ function withContextSync(metadata, fn) {
|
|
|
205
203
|
* ```
|
|
206
204
|
*/
|
|
207
205
|
function WithContext(metadata) {
|
|
208
|
-
return
|
|
206
|
+
return (_target, _propertyKey, descriptor) => {
|
|
209
207
|
const originalMethod = descriptor.value;
|
|
210
208
|
descriptor.value = async function (...args) {
|
|
211
209
|
return withContext(metadata, () => originalMethod.apply(this, args));
|
package/dist/errors.d.ts
CHANGED
|
@@ -47,6 +47,8 @@ export declare class EvalAIError extends Error {
|
|
|
47
47
|
retryAfter?: number;
|
|
48
48
|
/** When the limit resets (for feature limit errors) */
|
|
49
49
|
resetAt?: Date;
|
|
50
|
+
/** Request ID from API (for correlation/debugging) */
|
|
51
|
+
requestId?: string;
|
|
50
52
|
constructor(message: string, code: string, statusCode: number, details?: any);
|
|
51
53
|
/**
|
|
52
54
|
* Get formatted error message with solutions
|
package/dist/errors.js
CHANGED
|
@@ -11,126 +11,126 @@ exports.createErrorFromResponse = createErrorFromResponse;
|
|
|
11
11
|
*/
|
|
12
12
|
const ERROR_DOCS = {
|
|
13
13
|
MISSING_API_KEY: {
|
|
14
|
-
code:
|
|
15
|
-
message:
|
|
16
|
-
documentation:
|
|
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
17
|
solutions: [
|
|
18
|
-
|
|
18
|
+
"Set EVALAI_API_KEY environment variable",
|
|
19
19
|
'Pass apiKey in config: new AIEvalClient({ apiKey: "..." })',
|
|
20
|
-
|
|
20
|
+
"Get your API key from https://platform.ai-eval-platform.com/settings/api-keys",
|
|
21
21
|
],
|
|
22
|
-
retryable: false
|
|
22
|
+
retryable: false,
|
|
23
23
|
},
|
|
24
24
|
MISSING_ORGANIZATION_ID: {
|
|
25
|
-
code:
|
|
26
|
-
message:
|
|
27
|
-
documentation:
|
|
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
28
|
solutions: [
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
"Set EVALAI_ORGANIZATION_ID environment variable",
|
|
30
|
+
"Pass organizationId in config: new AIEvalClient({ organizationId: 123 })",
|
|
31
|
+
"Pass organizationId in method params",
|
|
32
32
|
],
|
|
33
|
-
retryable: false
|
|
33
|
+
retryable: false,
|
|
34
34
|
},
|
|
35
35
|
RATE_LIMIT_EXCEEDED: {
|
|
36
|
-
code:
|
|
37
|
-
message:
|
|
38
|
-
documentation:
|
|
36
|
+
code: "RATE_LIMIT_EXCEEDED",
|
|
37
|
+
message: "Rate limit exceeded",
|
|
38
|
+
documentation: "https://docs.ai-eval-platform.com/errors/rate-limit",
|
|
39
39
|
solutions: [
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
"Wait before retrying (check retryAfter property)",
|
|
41
|
+
"Upgrade your plan for higher rate limits",
|
|
42
|
+
"Implement exponential backoff in your application",
|
|
43
43
|
],
|
|
44
|
-
retryable: true
|
|
44
|
+
retryable: true,
|
|
45
45
|
},
|
|
46
46
|
TIMEOUT: {
|
|
47
|
-
code:
|
|
48
|
-
message:
|
|
49
|
-
documentation:
|
|
47
|
+
code: "TIMEOUT",
|
|
48
|
+
message: "Request timed out",
|
|
49
|
+
documentation: "https://docs.ai-eval-platform.com/errors/timeout",
|
|
50
50
|
solutions: [
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
"Increase timeout: new AIEvalClient({ timeout: 60000 })",
|
|
52
|
+
"Check your network connection",
|
|
53
|
+
"The service may be experiencing high load",
|
|
54
54
|
],
|
|
55
|
-
retryable: true
|
|
55
|
+
retryable: true,
|
|
56
56
|
},
|
|
57
57
|
NETWORK_ERROR: {
|
|
58
|
-
code:
|
|
59
|
-
message:
|
|
60
|
-
documentation:
|
|
58
|
+
code: "NETWORK_ERROR",
|
|
59
|
+
message: "Network connectivity issue",
|
|
60
|
+
documentation: "https://docs.ai-eval-platform.com/errors/network",
|
|
61
61
|
solutions: [
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
"Check your internet connection",
|
|
63
|
+
"Verify the baseUrl is correct",
|
|
64
|
+
"Check if you can reach the API endpoint",
|
|
65
65
|
],
|
|
66
|
-
retryable: true
|
|
66
|
+
retryable: true,
|
|
67
67
|
},
|
|
68
68
|
UNAUTHORIZED: {
|
|
69
|
-
code:
|
|
70
|
-
message:
|
|
71
|
-
documentation:
|
|
69
|
+
code: "UNAUTHORIZED",
|
|
70
|
+
message: "Authentication failed",
|
|
71
|
+
documentation: "https://docs.ai-eval-platform.com/errors/unauthorized",
|
|
72
72
|
solutions: [
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
76
|
],
|
|
77
|
-
retryable: false
|
|
77
|
+
retryable: false,
|
|
78
78
|
},
|
|
79
79
|
FORBIDDEN: {
|
|
80
|
-
code:
|
|
81
|
-
message:
|
|
82
|
-
documentation:
|
|
80
|
+
code: "FORBIDDEN",
|
|
81
|
+
message: "Access forbidden",
|
|
82
|
+
documentation: "https://docs.ai-eval-platform.com/errors/forbidden",
|
|
83
83
|
solutions: [
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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
87
|
],
|
|
88
|
-
retryable: false
|
|
88
|
+
retryable: false,
|
|
89
89
|
},
|
|
90
90
|
NOT_FOUND: {
|
|
91
|
-
code:
|
|
92
|
-
message:
|
|
93
|
-
documentation:
|
|
91
|
+
code: "NOT_FOUND",
|
|
92
|
+
message: "Resource not found",
|
|
93
|
+
documentation: "https://docs.ai-eval-platform.com/errors/not-found",
|
|
94
94
|
solutions: [
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
"Verify the resource ID is correct",
|
|
96
|
+
"Check if the resource was deleted",
|
|
97
|
+
"Ensure you're querying the correct organization",
|
|
98
98
|
],
|
|
99
|
-
retryable: false
|
|
99
|
+
retryable: false,
|
|
100
100
|
},
|
|
101
101
|
VALIDATION_ERROR: {
|
|
102
|
-
code:
|
|
103
|
-
message:
|
|
104
|
-
documentation:
|
|
102
|
+
code: "VALIDATION_ERROR",
|
|
103
|
+
message: "Request validation failed",
|
|
104
|
+
documentation: "https://docs.ai-eval-platform.com/errors/validation",
|
|
105
105
|
solutions: [
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
109
|
],
|
|
110
|
-
retryable: false
|
|
110
|
+
retryable: false,
|
|
111
111
|
},
|
|
112
112
|
INTERNAL_SERVER_ERROR: {
|
|
113
|
-
code:
|
|
114
|
-
message:
|
|
115
|
-
documentation:
|
|
113
|
+
code: "INTERNAL_SERVER_ERROR",
|
|
114
|
+
message: "Internal server error",
|
|
115
|
+
documentation: "https://docs.ai-eval-platform.com/errors/server-error",
|
|
116
116
|
solutions: [
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
120
|
],
|
|
121
|
-
retryable: true
|
|
121
|
+
retryable: true,
|
|
122
122
|
},
|
|
123
123
|
FEATURE_LIMIT_REACHED: {
|
|
124
|
-
code:
|
|
125
|
-
message:
|
|
126
|
-
documentation:
|
|
124
|
+
code: "FEATURE_LIMIT_REACHED",
|
|
125
|
+
message: "Feature usage limit reached",
|
|
126
|
+
documentation: "https://docs.ai-eval-platform.com/errors/feature-limit",
|
|
127
127
|
solutions: [
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
128
|
+
"Upgrade your plan for higher limits",
|
|
129
|
+
"Wait for your usage to reset (check resetAt property)",
|
|
130
|
+
"Optimize your usage patterns",
|
|
131
131
|
],
|
|
132
|
-
retryable: false
|
|
133
|
-
}
|
|
132
|
+
retryable: false,
|
|
133
|
+
},
|
|
134
134
|
};
|
|
135
135
|
/**
|
|
136
136
|
* Enhanced SDK Error class with rich error information and documentation
|
|
@@ -156,7 +156,7 @@ const ERROR_DOCS = {
|
|
|
156
156
|
class EvalAIError extends Error {
|
|
157
157
|
constructor(message, code, statusCode, details) {
|
|
158
158
|
super(message);
|
|
159
|
-
this.name =
|
|
159
|
+
this.name = "EvalAIError";
|
|
160
160
|
this.code = code;
|
|
161
161
|
this.statusCode = statusCode;
|
|
162
162
|
this.details = details;
|
|
@@ -168,18 +168,19 @@ class EvalAIError extends Error {
|
|
|
168
168
|
this.retryable = errorDoc.retryable;
|
|
169
169
|
}
|
|
170
170
|
else {
|
|
171
|
-
this.documentation =
|
|
172
|
-
this.solutions = [
|
|
171
|
+
this.documentation = "https://docs.ai-eval-platform.com/errors";
|
|
172
|
+
this.solutions = ["Check the API documentation for more information"];
|
|
173
173
|
this.retryable = false;
|
|
174
174
|
}
|
|
175
175
|
// Extract retry-after for rate limits
|
|
176
|
-
if (code ===
|
|
176
|
+
if (code === "RATE_LIMIT_EXCEEDED" && details?.retryAfter) {
|
|
177
177
|
this.retryAfter = details.retryAfter;
|
|
178
178
|
}
|
|
179
179
|
// Extract reset time for feature limits
|
|
180
|
-
if (code ===
|
|
180
|
+
if (code === "FEATURE_LIMIT_REACHED" && details?.resetAt) {
|
|
181
181
|
this.resetAt = new Date(details.resetAt);
|
|
182
182
|
}
|
|
183
|
+
this.requestId = details?.error?.requestId ?? details?.requestId;
|
|
183
184
|
// Ensure proper prototype chain
|
|
184
185
|
Object.setPrototypeOf(this, EvalAIError.prototype);
|
|
185
186
|
}
|
|
@@ -189,7 +190,7 @@ class EvalAIError extends Error {
|
|
|
189
190
|
getDetailedMessage() {
|
|
190
191
|
let msg = `${this.code}: ${this.message}\n\n`;
|
|
191
192
|
msg += `Documentation: ${this.documentation}\n\n`;
|
|
192
|
-
msg +=
|
|
193
|
+
msg += "Suggested solutions:\n";
|
|
193
194
|
this.solutions.forEach((solution, i) => {
|
|
194
195
|
msg += ` ${i + 1}. ${solution}\n`;
|
|
195
196
|
});
|
|
@@ -221,7 +222,8 @@ class EvalAIError extends Error {
|
|
|
221
222
|
retryable: this.retryable,
|
|
222
223
|
retryAfter: this.retryAfter,
|
|
223
224
|
resetAt: this.resetAt,
|
|
224
|
-
|
|
225
|
+
requestId: this.requestId,
|
|
226
|
+
details: this.details,
|
|
225
227
|
};
|
|
226
228
|
}
|
|
227
229
|
}
|
|
@@ -232,53 +234,60 @@ exports.SDKError = EvalAIError;
|
|
|
232
234
|
*/
|
|
233
235
|
function createErrorFromResponse(response, data) {
|
|
234
236
|
const status = response.status;
|
|
235
|
-
|
|
236
|
-
let
|
|
237
|
-
|
|
238
|
-
|
|
237
|
+
const errObj = data?.error && typeof data.error === "object" ? data.error : data;
|
|
238
|
+
let code = errObj?.code ?? data?.code ?? "UNKNOWN_ERROR";
|
|
239
|
+
const message = typeof data?.error === "string"
|
|
240
|
+
? data.error
|
|
241
|
+
: (errObj?.message ?? data?.message ?? response.statusText);
|
|
242
|
+
const requestId = errObj?.requestId ?? data?.requestId ?? response.headers.get("x-request-id") ?? undefined;
|
|
243
|
+
// Map HTTP status to error codes when code not in response
|
|
244
|
+
if (!errObj?.code && !data?.code) {
|
|
239
245
|
if (status === 401)
|
|
240
|
-
code =
|
|
246
|
+
code = "UNAUTHORIZED";
|
|
241
247
|
else if (status === 403)
|
|
242
|
-
code =
|
|
248
|
+
code = "FORBIDDEN";
|
|
243
249
|
else if (status === 404)
|
|
244
|
-
code =
|
|
250
|
+
code = "NOT_FOUND";
|
|
245
251
|
else if (status === 408)
|
|
246
|
-
code =
|
|
252
|
+
code = "TIMEOUT";
|
|
247
253
|
else if (status === 422)
|
|
248
|
-
code =
|
|
254
|
+
code = "VALIDATION_ERROR";
|
|
249
255
|
else if (status === 429)
|
|
250
|
-
code =
|
|
256
|
+
code = "RATE_LIMIT_EXCEEDED";
|
|
251
257
|
else if (status >= 500)
|
|
252
|
-
code =
|
|
258
|
+
code = "INTERNAL_SERVER_ERROR";
|
|
253
259
|
}
|
|
254
|
-
|
|
260
|
+
const err = new EvalAIError(message, code, status, data);
|
|
261
|
+
if (requestId)
|
|
262
|
+
err.requestId = requestId;
|
|
263
|
+
return err;
|
|
255
264
|
}
|
|
256
265
|
// Specific error types
|
|
257
266
|
class RateLimitError extends EvalAIError {
|
|
258
267
|
constructor(message, retryAfter) {
|
|
259
|
-
super(message,
|
|
260
|
-
this.name =
|
|
268
|
+
super(message, "RATE_LIMIT_EXCEEDED", 429, { retryAfter });
|
|
269
|
+
this.name = "RateLimitError";
|
|
261
270
|
}
|
|
262
271
|
}
|
|
263
272
|
exports.RateLimitError = RateLimitError;
|
|
264
273
|
class AuthenticationError extends EvalAIError {
|
|
265
|
-
constructor(message =
|
|
266
|
-
super(message,
|
|
267
|
-
this.name =
|
|
274
|
+
constructor(message = "Authentication failed") {
|
|
275
|
+
super(message, "AUTHENTICATION_ERROR", 401);
|
|
276
|
+
this.name = "AuthenticationError";
|
|
268
277
|
}
|
|
269
278
|
}
|
|
270
279
|
exports.AuthenticationError = AuthenticationError;
|
|
271
280
|
class ValidationError extends EvalAIError {
|
|
272
|
-
constructor(message =
|
|
273
|
-
super(message,
|
|
274
|
-
this.name =
|
|
281
|
+
constructor(message = "Validation failed", details) {
|
|
282
|
+
super(message, "VALIDATION_ERROR", 400, details);
|
|
283
|
+
this.name = "ValidationError";
|
|
275
284
|
}
|
|
276
285
|
}
|
|
277
286
|
exports.ValidationError = ValidationError;
|
|
278
287
|
class NetworkError extends EvalAIError {
|
|
279
|
-
constructor(message =
|
|
280
|
-
super(message,
|
|
281
|
-
this.name =
|
|
288
|
+
constructor(message = "Network request failed") {
|
|
289
|
+
super(message, "NETWORK_ERROR", 0);
|
|
290
|
+
this.name = "NetworkError";
|
|
282
291
|
this.retryable = true;
|
|
283
292
|
}
|
|
284
293
|
}
|
package/dist/export.d.ts
CHANGED
|
@@ -20,13 +20,13 @@
|
|
|
20
20
|
* await importFromLangSmith(client, langsmithData);
|
|
21
21
|
* ```
|
|
22
22
|
*/
|
|
23
|
-
import type { AIEvalClient } from
|
|
24
|
-
import type {
|
|
25
|
-
export type ExportFormat =
|
|
23
|
+
import type { AIEvalClient } from "./client";
|
|
24
|
+
import type { Evaluation, EvaluationRun, TestCase, Trace } from "./types";
|
|
25
|
+
export type ExportFormat = "json" | "csv" | "jsonl";
|
|
26
26
|
export type { ExportFormat as ExportType };
|
|
27
27
|
export interface ExportOptions {
|
|
28
28
|
/** Export format */
|
|
29
|
-
format:
|
|
29
|
+
format: "json" | "csv" | "jsonl";
|
|
30
30
|
/** Include traces */
|
|
31
31
|
includeTraces?: boolean;
|
|
32
32
|
/** Include evaluations */
|
|
@@ -152,7 +152,7 @@ export declare function importData(client: AIEvalClient, data: ExportData, optio
|
|
|
152
152
|
* });
|
|
153
153
|
* ```
|
|
154
154
|
*/
|
|
155
|
-
export declare function exportToFile(client: AIEvalClient, filePath: string, options: Omit<ExportOptions,
|
|
155
|
+
export declare function exportToFile(client: AIEvalClient, filePath: string, options: Omit<ExportOptions, "format">): Promise<void>;
|
|
156
156
|
/**
|
|
157
157
|
* Import data from JSON file
|
|
158
158
|
*
|
|
@@ -192,4 +192,4 @@ export declare function importFromLangSmith(client: AIEvalClient, langsmithData:
|
|
|
192
192
|
* fs.writeFileSync('traces.csv', csv);
|
|
193
193
|
* ```
|
|
194
194
|
*/
|
|
195
|
-
export declare function convertToCSV(data: ExportData, type:
|
|
195
|
+
export declare function convertToCSV(data: ExportData, type: "traces" | "evaluations"): string;
|
package/dist/export.js
CHANGED
|
@@ -81,16 +81,16 @@ async function exportData(client, options) {
|
|
|
81
81
|
const exportData = {
|
|
82
82
|
metadata: {
|
|
83
83
|
exportedAt: new Date().toISOString(),
|
|
84
|
-
version:
|
|
84
|
+
version: "1.0.0",
|
|
85
85
|
format: options.format,
|
|
86
|
-
organizationId: options.organizationId
|
|
87
|
-
}
|
|
86
|
+
organizationId: options.organizationId,
|
|
87
|
+
},
|
|
88
88
|
};
|
|
89
89
|
// Export traces
|
|
90
90
|
if (options.includeTraces) {
|
|
91
91
|
const traces = await client.traces.list({
|
|
92
92
|
organizationId: options.organizationId,
|
|
93
|
-
limit: options.limit
|
|
93
|
+
limit: options.limit,
|
|
94
94
|
});
|
|
95
95
|
exportData.traces = traces;
|
|
96
96
|
}
|
|
@@ -98,7 +98,7 @@ async function exportData(client, options) {
|
|
|
98
98
|
if (options.includeEvaluations) {
|
|
99
99
|
const evaluations = await client.evaluations.list({
|
|
100
100
|
organizationId: options.organizationId,
|
|
101
|
-
limit: options.limit
|
|
101
|
+
limit: options.limit,
|
|
102
102
|
});
|
|
103
103
|
exportData.evaluations = evaluations;
|
|
104
104
|
// Export test cases for each evaluation
|
|
@@ -140,7 +140,7 @@ async function importData(client, data, options) {
|
|
|
140
140
|
const result = {
|
|
141
141
|
summary: { total: 0, imported: 0, skipped: 0, failed: 0 },
|
|
142
142
|
details: {},
|
|
143
|
-
errors: []
|
|
143
|
+
errors: [],
|
|
144
144
|
};
|
|
145
145
|
if (options.dryRun) {
|
|
146
146
|
// Count what would be imported
|
|
@@ -165,13 +165,15 @@ async function importData(client, data, options) {
|
|
|
165
165
|
organizationId: options.organizationId || trace.organizationId,
|
|
166
166
|
status: trace.status,
|
|
167
167
|
durationMs: trace.durationMs || undefined,
|
|
168
|
-
metadata: trace.metadata || undefined
|
|
168
|
+
metadata: trace.metadata || undefined,
|
|
169
169
|
});
|
|
170
170
|
traceResults.imported++;
|
|
171
171
|
result.summary.imported++;
|
|
172
172
|
}
|
|
173
173
|
catch (error) {
|
|
174
|
-
if (options.skipDuplicates &&
|
|
174
|
+
if (options.skipDuplicates &&
|
|
175
|
+
error instanceof Error &&
|
|
176
|
+
error.message.includes("already exists")) {
|
|
175
177
|
traceResults.skipped++;
|
|
176
178
|
result.summary.skipped++;
|
|
177
179
|
}
|
|
@@ -180,7 +182,7 @@ async function importData(client, data, options) {
|
|
|
180
182
|
result.summary.failed++;
|
|
181
183
|
result.errors?.push({
|
|
182
184
|
item: `trace:${trace.traceId}`,
|
|
183
|
-
error: error instanceof Error ? error.message : String(error)
|
|
185
|
+
error: error instanceof Error ? error.message : String(error),
|
|
184
186
|
});
|
|
185
187
|
}
|
|
186
188
|
}
|
|
@@ -194,7 +196,7 @@ async function importData(client, data, options) {
|
|
|
194
196
|
for (const evaluation of data.evaluations) {
|
|
195
197
|
try {
|
|
196
198
|
if (!options.createdBy) {
|
|
197
|
-
throw new Error(
|
|
199
|
+
throw new Error("createdBy is required for importing evaluations");
|
|
198
200
|
}
|
|
199
201
|
await client.evaluations.create({
|
|
200
202
|
name: evaluation.name,
|
|
@@ -202,13 +204,15 @@ async function importData(client, data, options) {
|
|
|
202
204
|
type: evaluation.type,
|
|
203
205
|
organizationId: options.organizationId || evaluation.organizationId,
|
|
204
206
|
createdBy: options.createdBy,
|
|
205
|
-
status: evaluation.status
|
|
207
|
+
status: evaluation.status,
|
|
206
208
|
});
|
|
207
209
|
evalResults.imported++;
|
|
208
210
|
result.summary.imported++;
|
|
209
211
|
}
|
|
210
212
|
catch (error) {
|
|
211
|
-
if (options.skipDuplicates &&
|
|
213
|
+
if (options.skipDuplicates &&
|
|
214
|
+
error instanceof Error &&
|
|
215
|
+
error.message.includes("already exists")) {
|
|
212
216
|
evalResults.skipped++;
|
|
213
217
|
result.summary.skipped++;
|
|
214
218
|
}
|
|
@@ -217,7 +221,7 @@ async function importData(client, data, options) {
|
|
|
217
221
|
result.summary.failed++;
|
|
218
222
|
result.errors?.push({
|
|
219
223
|
item: `evaluation:${evaluation.name}`,
|
|
220
|
-
error: error instanceof Error ? error.message : String(error)
|
|
224
|
+
error: error instanceof Error ? error.message : String(error),
|
|
221
225
|
});
|
|
222
226
|
}
|
|
223
227
|
}
|
|
@@ -239,8 +243,8 @@ async function importData(client, data, options) {
|
|
|
239
243
|
* ```
|
|
240
244
|
*/
|
|
241
245
|
async function exportToFile(client, filePath, options) {
|
|
242
|
-
const data = await exportData(client, { ...options, format:
|
|
243
|
-
const fs = await Promise.resolve().then(() => __importStar(require(
|
|
246
|
+
const data = await exportData(client, { ...options, format: "json" });
|
|
247
|
+
const fs = await Promise.resolve().then(() => __importStar(require("node:fs")));
|
|
244
248
|
fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
|
|
245
249
|
}
|
|
246
250
|
/**
|
|
@@ -255,8 +259,8 @@ async function exportToFile(client, filePath, options) {
|
|
|
255
259
|
* ```
|
|
256
260
|
*/
|
|
257
261
|
async function importFromFile(client, filePath, options) {
|
|
258
|
-
const fs = await Promise.resolve().then(() => __importStar(require(
|
|
259
|
-
const content = fs.readFileSync(filePath,
|
|
262
|
+
const fs = await Promise.resolve().then(() => __importStar(require("node:fs")));
|
|
263
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
260
264
|
const data = JSON.parse(content);
|
|
261
265
|
return importData(client, data, options);
|
|
262
266
|
}
|
|
@@ -281,27 +285,27 @@ async function importFromLangSmith(client, langsmithData, options) {
|
|
|
281
285
|
const transformedData = {
|
|
282
286
|
metadata: {
|
|
283
287
|
exportedAt: new Date().toISOString(),
|
|
284
|
-
version:
|
|
285
|
-
format:
|
|
286
|
-
organizationId: options.organizationId
|
|
288
|
+
version: "1.0.0",
|
|
289
|
+
format: "json",
|
|
290
|
+
organizationId: options.organizationId,
|
|
287
291
|
},
|
|
288
|
-
traces: []
|
|
292
|
+
traces: [],
|
|
289
293
|
};
|
|
290
294
|
// Transform runs to traces
|
|
291
295
|
if (langsmithData.runs && Array.isArray(langsmithData.runs)) {
|
|
292
296
|
transformedData.traces = langsmithData.runs.map((run) => ({
|
|
293
|
-
name: run.name ||
|
|
297
|
+
name: run.name || "Imported Trace",
|
|
294
298
|
traceId: run.id || `langsmith-${Date.now()}-${Math.random()}`,
|
|
295
299
|
organizationId: options.organizationId,
|
|
296
|
-
status: run.error ?
|
|
300
|
+
status: run.error ? "error" : "success",
|
|
297
301
|
durationMs: run.execution_time ? Math.round(run.execution_time * 1000) : null,
|
|
298
302
|
metadata: {
|
|
299
|
-
source:
|
|
303
|
+
source: "langsmith",
|
|
300
304
|
original_id: run.id,
|
|
301
305
|
inputs: run.inputs,
|
|
302
|
-
outputs: run.outputs
|
|
306
|
+
outputs: run.outputs,
|
|
303
307
|
},
|
|
304
|
-
createdAt: run.start_time || new Date().toISOString()
|
|
308
|
+
createdAt: run.start_time || new Date().toISOString(),
|
|
305
309
|
}));
|
|
306
310
|
}
|
|
307
311
|
return importData(client, transformedData, options);
|
|
@@ -317,18 +321,20 @@ async function importFromLangSmith(client, langsmithData, options) {
|
|
|
317
321
|
* ```
|
|
318
322
|
*/
|
|
319
323
|
function convertToCSV(data, type) {
|
|
320
|
-
const items = type ===
|
|
324
|
+
const items = type === "traces" ? data.traces : data.evaluations;
|
|
321
325
|
if (!items || items.length === 0)
|
|
322
|
-
return
|
|
326
|
+
return "";
|
|
323
327
|
// Get headers from first item
|
|
324
328
|
const headers = Object.keys(items[0]);
|
|
325
|
-
const rows = items.map(item => headers
|
|
329
|
+
const rows = items.map((item) => headers
|
|
330
|
+
.map((h) => {
|
|
326
331
|
const value = item[h];
|
|
327
332
|
if (value === null || value === undefined)
|
|
328
|
-
return
|
|
329
|
-
if (typeof value ===
|
|
333
|
+
return "";
|
|
334
|
+
if (typeof value === "object")
|
|
330
335
|
return JSON.stringify(value);
|
|
331
336
|
return String(value);
|
|
332
|
-
})
|
|
333
|
-
|
|
337
|
+
})
|
|
338
|
+
.join(","));
|
|
339
|
+
return [headers.join(","), ...rows].join("\n");
|
|
334
340
|
}
|