@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/assertions.d.ts
CHANGED
|
@@ -76,7 +76,7 @@ export declare class Expectation {
|
|
|
76
76
|
* Assert value has expected sentiment
|
|
77
77
|
* @example expect(output).toHaveSentiment('positive')
|
|
78
78
|
*/
|
|
79
|
-
toHaveSentiment(expected:
|
|
79
|
+
toHaveSentiment(expected: "positive" | "negative" | "neutral", message?: string): AssertionResult;
|
|
80
80
|
/**
|
|
81
81
|
* Assert string length is within range
|
|
82
82
|
* @example expect(output).toHaveLength({ min: 10, max: 100 })
|
|
@@ -172,7 +172,7 @@ export declare function hasLength(text: string, range: {
|
|
|
172
172
|
}): boolean;
|
|
173
173
|
export declare function containsJSON(text: string): boolean;
|
|
174
174
|
export declare function notContainsPII(text: string): boolean;
|
|
175
|
-
export declare function hasSentiment(text: string, expected:
|
|
175
|
+
export declare function hasSentiment(text: string, expected: "positive" | "negative" | "neutral"): boolean;
|
|
176
176
|
export declare function similarTo(text1: string, text2: string, threshold?: number): boolean;
|
|
177
177
|
export declare function withinRange(value: number, min: number, max: number): boolean;
|
|
178
178
|
export declare function isValidEmail(email: string): boolean;
|
package/dist/assertions.js
CHANGED
|
@@ -67,7 +67,10 @@ class Expectation {
|
|
|
67
67
|
passed,
|
|
68
68
|
expected,
|
|
69
69
|
actual: this.value,
|
|
70
|
-
message: message ||
|
|
70
|
+
message: message ||
|
|
71
|
+
(passed
|
|
72
|
+
? "Values are equal"
|
|
73
|
+
: `Expected ${JSON.stringify(expected)}, got ${JSON.stringify(this.value)}`),
|
|
71
74
|
};
|
|
72
75
|
}
|
|
73
76
|
/**
|
|
@@ -82,7 +85,8 @@ class Expectation {
|
|
|
82
85
|
passed,
|
|
83
86
|
expected: substring,
|
|
84
87
|
actual: text,
|
|
85
|
-
message: message ||
|
|
88
|
+
message: message ||
|
|
89
|
+
(passed ? `Text contains "${substring}"` : `Text does not contain "${substring}"`),
|
|
86
90
|
};
|
|
87
91
|
}
|
|
88
92
|
/**
|
|
@@ -91,14 +95,15 @@ class Expectation {
|
|
|
91
95
|
*/
|
|
92
96
|
toContainKeywords(keywords, message) {
|
|
93
97
|
const text = String(this.value).toLowerCase();
|
|
94
|
-
const missingKeywords = keywords.filter(k => !text.includes(k.toLowerCase()));
|
|
98
|
+
const missingKeywords = keywords.filter((k) => !text.includes(k.toLowerCase()));
|
|
95
99
|
const passed = missingKeywords.length === 0;
|
|
96
100
|
return {
|
|
97
101
|
name: "toContainKeywords",
|
|
98
102
|
passed,
|
|
99
103
|
expected: keywords,
|
|
100
104
|
actual: text,
|
|
101
|
-
message: message ||
|
|
105
|
+
message: message ||
|
|
106
|
+
(passed ? `Contains all keywords` : `Missing keywords: ${missingKeywords.join(", ")}`),
|
|
102
107
|
};
|
|
103
108
|
}
|
|
104
109
|
/**
|
|
@@ -113,7 +118,8 @@ class Expectation {
|
|
|
113
118
|
passed,
|
|
114
119
|
expected: `not containing "${substring}"`,
|
|
115
120
|
actual: text,
|
|
116
|
-
message: message ||
|
|
121
|
+
message: message ||
|
|
122
|
+
(passed ? `Text does not contain "${substring}"` : `Text contains "${substring}"`),
|
|
117
123
|
};
|
|
118
124
|
}
|
|
119
125
|
/**
|
|
@@ -127,18 +133,18 @@ class Expectation {
|
|
|
127
133
|
const ssnPattern = /\b\d{3}-\d{2}-\d{4}\b/;
|
|
128
134
|
const foundPII = [];
|
|
129
135
|
if (emailPattern.test(text))
|
|
130
|
-
foundPII.push(
|
|
136
|
+
foundPII.push("email");
|
|
131
137
|
if (phonePattern.test(text))
|
|
132
|
-
foundPII.push(
|
|
138
|
+
foundPII.push("phone number");
|
|
133
139
|
if (ssnPattern.test(text))
|
|
134
|
-
foundPII.push(
|
|
140
|
+
foundPII.push("SSN");
|
|
135
141
|
const passed = foundPII.length === 0;
|
|
136
142
|
return {
|
|
137
143
|
name: "toNotContainPII",
|
|
138
144
|
passed,
|
|
139
145
|
expected: "no PII",
|
|
140
|
-
actual: foundPII.length > 0 ? `Found: ${foundPII.join(
|
|
141
|
-
message: message || (passed ? "No PII detected" : `PII detected: ${foundPII.join(
|
|
146
|
+
actual: foundPII.length > 0 ? `Found: ${foundPII.join(", ")}` : "no PII",
|
|
147
|
+
message: message || (passed ? "No PII detected" : `PII detected: ${foundPII.join(", ")}`),
|
|
142
148
|
};
|
|
143
149
|
}
|
|
144
150
|
/**
|
|
@@ -153,7 +159,7 @@ class Expectation {
|
|
|
153
159
|
passed,
|
|
154
160
|
expected: pattern.toString(),
|
|
155
161
|
actual: text,
|
|
156
|
-
message: message || (passed ? `Matches pattern ${pattern}` : `Does not match pattern ${pattern}`)
|
|
162
|
+
message: message || (passed ? `Matches pattern ${pattern}` : `Does not match pattern ${pattern}`),
|
|
157
163
|
};
|
|
158
164
|
}
|
|
159
165
|
/**
|
|
@@ -167,7 +173,7 @@ class Expectation {
|
|
|
167
173
|
parsedJson = JSON.parse(String(this.value));
|
|
168
174
|
passed = true;
|
|
169
175
|
}
|
|
170
|
-
catch (
|
|
176
|
+
catch (_e) {
|
|
171
177
|
passed = false;
|
|
172
178
|
}
|
|
173
179
|
return {
|
|
@@ -175,7 +181,7 @@ class Expectation {
|
|
|
175
181
|
passed,
|
|
176
182
|
expected: "valid JSON",
|
|
177
183
|
actual: passed ? parsedJson : this.value,
|
|
178
|
-
message: message || (passed ? "Valid JSON" : "Invalid JSON")
|
|
184
|
+
message: message || (passed ? "Valid JSON" : "Invalid JSON"),
|
|
179
185
|
};
|
|
180
186
|
}
|
|
181
187
|
/**
|
|
@@ -189,9 +195,9 @@ class Expectation {
|
|
|
189
195
|
parsedJson = JSON.parse(String(this.value));
|
|
190
196
|
const requiredKeys = Object.keys(schema);
|
|
191
197
|
const actualKeys = Object.keys(parsedJson);
|
|
192
|
-
passed = requiredKeys.every(key => actualKeys.includes(key));
|
|
198
|
+
passed = requiredKeys.every((key) => actualKeys.includes(key));
|
|
193
199
|
}
|
|
194
|
-
catch (
|
|
200
|
+
catch (_e) {
|
|
195
201
|
passed = false;
|
|
196
202
|
}
|
|
197
203
|
return {
|
|
@@ -199,7 +205,7 @@ class Expectation {
|
|
|
199
205
|
passed,
|
|
200
206
|
expected: schema,
|
|
201
207
|
actual: parsedJson,
|
|
202
|
-
message: message || (passed ? "JSON matches schema" : "JSON does not match schema")
|
|
208
|
+
message: message || (passed ? "JSON matches schema" : "JSON does not match schema"),
|
|
203
209
|
};
|
|
204
210
|
}
|
|
205
211
|
/**
|
|
@@ -208,24 +214,46 @@ class Expectation {
|
|
|
208
214
|
*/
|
|
209
215
|
toHaveSentiment(expected, message) {
|
|
210
216
|
const text = String(this.value).toLowerCase();
|
|
211
|
-
const positiveWords = [
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
217
|
+
const positiveWords = [
|
|
218
|
+
"good",
|
|
219
|
+
"great",
|
|
220
|
+
"excellent",
|
|
221
|
+
"amazing",
|
|
222
|
+
"wonderful",
|
|
223
|
+
"fantastic",
|
|
224
|
+
"love",
|
|
225
|
+
"best",
|
|
226
|
+
"happy",
|
|
227
|
+
"helpful",
|
|
228
|
+
];
|
|
229
|
+
const negativeWords = [
|
|
230
|
+
"bad",
|
|
231
|
+
"terrible",
|
|
232
|
+
"awful",
|
|
233
|
+
"horrible",
|
|
234
|
+
"worst",
|
|
235
|
+
"hate",
|
|
236
|
+
"poor",
|
|
237
|
+
"disappointing",
|
|
238
|
+
"sad",
|
|
239
|
+
"useless",
|
|
240
|
+
];
|
|
241
|
+
const positiveCount = positiveWords.filter((w) => text.includes(w)).length;
|
|
242
|
+
const negativeCount = negativeWords.filter((w) => text.includes(w)).length;
|
|
215
243
|
let actual;
|
|
216
244
|
if (positiveCount > negativeCount)
|
|
217
|
-
actual =
|
|
245
|
+
actual = "positive";
|
|
218
246
|
else if (negativeCount > positiveCount)
|
|
219
|
-
actual =
|
|
247
|
+
actual = "negative";
|
|
220
248
|
else
|
|
221
|
-
actual =
|
|
249
|
+
actual = "neutral";
|
|
222
250
|
const passed = actual === expected;
|
|
223
251
|
return {
|
|
224
252
|
name: "toHaveSentiment",
|
|
225
253
|
passed,
|
|
226
254
|
expected,
|
|
227
255
|
actual,
|
|
228
|
-
message: message || (passed ? `Sentiment is ${expected}` : `Expected ${expected}, got ${actual}`)
|
|
256
|
+
message: message || (passed ? `Sentiment is ${expected}` : `Expected ${expected}, got ${actual}`),
|
|
229
257
|
};
|
|
230
258
|
}
|
|
231
259
|
/**
|
|
@@ -241,7 +269,7 @@ class Expectation {
|
|
|
241
269
|
passed,
|
|
242
270
|
expected: range,
|
|
243
271
|
actual: length,
|
|
244
|
-
message: message || (passed ? `Length ${length} is within range` : `Length ${length} not in range`)
|
|
272
|
+
message: message || (passed ? `Length ${length} is within range` : `Length ${length} not in range`),
|
|
245
273
|
};
|
|
246
274
|
}
|
|
247
275
|
/**
|
|
@@ -250,14 +278,15 @@ class Expectation {
|
|
|
250
278
|
*/
|
|
251
279
|
toNotHallucinate(groundTruth, message) {
|
|
252
280
|
const text = String(this.value).toLowerCase();
|
|
253
|
-
const missingFacts = groundTruth.filter(fact => !text.includes(fact.toLowerCase()));
|
|
281
|
+
const missingFacts = groundTruth.filter((fact) => !text.includes(fact.toLowerCase()));
|
|
254
282
|
const passed = missingFacts.length === 0;
|
|
255
283
|
return {
|
|
256
284
|
name: "toNotHallucinate",
|
|
257
285
|
passed,
|
|
258
286
|
expected: "all ground truth facts",
|
|
259
|
-
actual: missingFacts.length > 0 ? `Missing: ${missingFacts.join(
|
|
260
|
-
message: message ||
|
|
287
|
+
actual: missingFacts.length > 0 ? `Missing: ${missingFacts.join(", ")}` : "all facts present",
|
|
288
|
+
message: message ||
|
|
289
|
+
(passed ? "No hallucinations detected" : `Missing facts: ${missingFacts.join(", ")}`),
|
|
261
290
|
};
|
|
262
291
|
}
|
|
263
292
|
/**
|
|
@@ -272,7 +301,7 @@ class Expectation {
|
|
|
272
301
|
passed,
|
|
273
302
|
expected: `<= ${maxMs}ms`,
|
|
274
303
|
actual: `${duration}ms`,
|
|
275
|
-
message: message || (passed ? `${duration}ms within limit` : `${duration}ms exceeds ${maxMs}ms`)
|
|
304
|
+
message: message || (passed ? `${duration}ms within limit` : `${duration}ms exceeds ${maxMs}ms`),
|
|
276
305
|
};
|
|
277
306
|
}
|
|
278
307
|
/**
|
|
@@ -286,7 +315,7 @@ class Expectation {
|
|
|
286
315
|
passed,
|
|
287
316
|
expected: "truthy value",
|
|
288
317
|
actual: this.value,
|
|
289
|
-
message: message || (passed ? "Value is truthy" : "Value is falsy")
|
|
318
|
+
message: message || (passed ? "Value is truthy" : "Value is falsy"),
|
|
290
319
|
};
|
|
291
320
|
}
|
|
292
321
|
/**
|
|
@@ -294,13 +323,13 @@ class Expectation {
|
|
|
294
323
|
* @example expect(error).toBeFalsy()
|
|
295
324
|
*/
|
|
296
325
|
toBeFalsy(message) {
|
|
297
|
-
const passed = !
|
|
326
|
+
const passed = !this.value;
|
|
298
327
|
return {
|
|
299
328
|
name: "toBeFalsy",
|
|
300
329
|
passed,
|
|
301
330
|
expected: "falsy value",
|
|
302
331
|
actual: this.value,
|
|
303
|
-
message: message || (passed ? "Value is falsy" : "Value is truthy")
|
|
332
|
+
message: message || (passed ? "Value is falsy" : "Value is truthy"),
|
|
304
333
|
};
|
|
305
334
|
}
|
|
306
335
|
/**
|
|
@@ -315,7 +344,7 @@ class Expectation {
|
|
|
315
344
|
passed,
|
|
316
345
|
expected: `> ${expected}`,
|
|
317
346
|
actual: value,
|
|
318
|
-
message: message || (passed ? `${value} > ${expected}` : `${value} <= ${expected}`)
|
|
347
|
+
message: message || (passed ? `${value} > ${expected}` : `${value} <= ${expected}`),
|
|
319
348
|
};
|
|
320
349
|
}
|
|
321
350
|
/**
|
|
@@ -330,7 +359,7 @@ class Expectation {
|
|
|
330
359
|
passed,
|
|
331
360
|
expected: `< ${expected}`,
|
|
332
361
|
actual: value,
|
|
333
|
-
message: message || (passed ? `${value} < ${expected}` : `${value} >= ${expected}`)
|
|
362
|
+
message: message || (passed ? `${value} < ${expected}` : `${value} >= ${expected}`),
|
|
334
363
|
};
|
|
335
364
|
}
|
|
336
365
|
/**
|
|
@@ -345,7 +374,7 @@ class Expectation {
|
|
|
345
374
|
passed,
|
|
346
375
|
expected: `between ${min} and ${max}`,
|
|
347
376
|
actual: value,
|
|
348
|
-
message: message || (passed ? `${value} is within range` : `${value} is outside range`)
|
|
377
|
+
message: message || (passed ? `${value} is within range` : `${value} is outside range`),
|
|
349
378
|
};
|
|
350
379
|
}
|
|
351
380
|
/**
|
|
@@ -360,7 +389,7 @@ class Expectation {
|
|
|
360
389
|
passed: hasCodeBlock,
|
|
361
390
|
expected: "code block",
|
|
362
391
|
actual: text,
|
|
363
|
-
message: message || (hasCodeBlock ? "Contains code block" : "No code block found")
|
|
392
|
+
message: message || (hasCodeBlock ? "Contains code block" : "No code block found"),
|
|
364
393
|
};
|
|
365
394
|
}
|
|
366
395
|
/**
|
|
@@ -369,15 +398,16 @@ class Expectation {
|
|
|
369
398
|
*/
|
|
370
399
|
toBeProfessional(message) {
|
|
371
400
|
const text = String(this.value).toLowerCase();
|
|
372
|
-
const profanity = [
|
|
373
|
-
const foundProfanity = profanity.filter(word => text.includes(word));
|
|
401
|
+
const profanity = ["damn", "hell", "shit", "fuck", "ass", "bitch", "crap"];
|
|
402
|
+
const foundProfanity = profanity.filter((word) => text.includes(word));
|
|
374
403
|
const passed = foundProfanity.length === 0;
|
|
375
404
|
return {
|
|
376
405
|
name: "toBeProfessional",
|
|
377
406
|
passed,
|
|
378
407
|
expected: "professional tone",
|
|
379
|
-
actual: foundProfanity.length > 0 ? `Found: ${foundProfanity.join(
|
|
380
|
-
message: message ||
|
|
408
|
+
actual: foundProfanity.length > 0 ? `Found: ${foundProfanity.join(", ")}` : "professional",
|
|
409
|
+
message: message ||
|
|
410
|
+
(passed ? "Professional tone" : `Unprofessional language: ${foundProfanity.join(", ")}`),
|
|
381
411
|
};
|
|
382
412
|
}
|
|
383
413
|
/**
|
|
@@ -388,21 +418,21 @@ class Expectation {
|
|
|
388
418
|
const text = String(this.value);
|
|
389
419
|
const issues = [];
|
|
390
420
|
// Check for double spaces
|
|
391
|
-
if (/
|
|
392
|
-
issues.push(
|
|
421
|
+
if (/ {2,}/.test(text))
|
|
422
|
+
issues.push("double spaces");
|
|
393
423
|
// Check for missing periods at end
|
|
394
424
|
if (text.length > 10 && !/[.!?]$/.test(text.trim()))
|
|
395
|
-
issues.push(
|
|
425
|
+
issues.push("missing ending punctuation");
|
|
396
426
|
// Check for lowercase sentence starts
|
|
397
427
|
if (/\.\s+[a-z]/.test(text))
|
|
398
|
-
issues.push(
|
|
428
|
+
issues.push("lowercase after period");
|
|
399
429
|
const passed = issues.length === 0;
|
|
400
430
|
return {
|
|
401
431
|
name: "toHaveProperGrammar",
|
|
402
432
|
passed,
|
|
403
433
|
expected: "proper grammar",
|
|
404
|
-
actual: issues.length > 0 ? `Issues: ${issues.join(
|
|
405
|
-
message: message || (passed ? "Proper grammar" : `Grammar issues: ${issues.join(
|
|
434
|
+
actual: issues.length > 0 ? `Issues: ${issues.join(", ")}` : "proper grammar",
|
|
435
|
+
message: message || (passed ? "Proper grammar" : `Grammar issues: ${issues.join(", ")}`),
|
|
406
436
|
};
|
|
407
437
|
}
|
|
408
438
|
}
|
|
@@ -447,14 +477,14 @@ function runAssertions(assertions) {
|
|
|
447
477
|
passed: false,
|
|
448
478
|
expected: null,
|
|
449
479
|
actual: null,
|
|
450
|
-
message: error instanceof Error ? error.message : "Unknown error"
|
|
480
|
+
message: error instanceof Error ? error.message : "Unknown error",
|
|
451
481
|
};
|
|
452
482
|
}
|
|
453
483
|
});
|
|
454
484
|
}
|
|
455
485
|
// Standalone assertion functions
|
|
456
486
|
function containsKeywords(text, keywords) {
|
|
457
|
-
return keywords.every(keyword => text.toLowerCase().includes(keyword.toLowerCase()));
|
|
487
|
+
return keywords.every((keyword) => text.toLowerCase().includes(keyword.toLowerCase()));
|
|
458
488
|
}
|
|
459
489
|
function matchesPattern(text, pattern) {
|
|
460
490
|
return pattern.test(text);
|
|
@@ -485,18 +515,18 @@ function notContainsPII(text) {
|
|
|
485
515
|
/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/, // Email
|
|
486
516
|
/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/, // IP address
|
|
487
517
|
];
|
|
488
|
-
return !piiPatterns.some(pattern => pattern.test(text));
|
|
518
|
+
return !piiPatterns.some((pattern) => pattern.test(text));
|
|
489
519
|
}
|
|
490
520
|
function hasSentiment(text, expected) {
|
|
491
521
|
// This is a simplified implementation
|
|
492
|
-
const positiveWords = [
|
|
493
|
-
const negativeWords = [
|
|
522
|
+
const positiveWords = ["good", "great", "excellent", "awesome"];
|
|
523
|
+
const negativeWords = ["bad", "terrible", "awful", "poor"];
|
|
494
524
|
const words = text.toLowerCase().split(/\s+/);
|
|
495
|
-
const positiveCount = words.filter(word => positiveWords.includes(word)).length;
|
|
496
|
-
const negativeCount = words.filter(word => negativeWords.includes(word)).length;
|
|
497
|
-
if (expected ===
|
|
525
|
+
const positiveCount = words.filter((word) => positiveWords.includes(word)).length;
|
|
526
|
+
const negativeCount = words.filter((word) => negativeWords.includes(word)).length;
|
|
527
|
+
if (expected === "positive")
|
|
498
528
|
return positiveCount > negativeCount;
|
|
499
|
-
if (expected ===
|
|
529
|
+
if (expected === "negative")
|
|
500
530
|
return negativeCount > positiveCount;
|
|
501
531
|
return positiveCount === negativeCount; // neutral
|
|
502
532
|
}
|
|
@@ -504,7 +534,7 @@ function similarTo(text1, text2, threshold = 0.8) {
|
|
|
504
534
|
// Simple similarity check - in a real app, you'd use a proper string similarity algorithm
|
|
505
535
|
const words1 = new Set(text1.toLowerCase().split(/\s+/));
|
|
506
536
|
const words2 = new Set(text2.toLowerCase().split(/\s+/));
|
|
507
|
-
const intersection = new Set([...words1].filter(word => words2.has(word)));
|
|
537
|
+
const intersection = new Set([...words1].filter((word) => words2.has(word)));
|
|
508
538
|
const union = new Set([...words1, ...words2]);
|
|
509
539
|
return intersection.size / union.size >= threshold;
|
|
510
540
|
}
|
|
@@ -525,13 +555,13 @@ function isValidURL(url) {
|
|
|
525
555
|
}
|
|
526
556
|
function hasNoHallucinations(text, groundTruth) {
|
|
527
557
|
// This is a simplified implementation
|
|
528
|
-
return groundTruth.every(truth => text.includes(truth));
|
|
558
|
+
return groundTruth.every((truth) => text.includes(truth));
|
|
529
559
|
}
|
|
530
560
|
function matchesSchema(value, schema) {
|
|
531
561
|
// This is a simplified implementation
|
|
532
|
-
if (typeof value !==
|
|
562
|
+
if (typeof value !== "object" || value === null)
|
|
533
563
|
return false;
|
|
534
|
-
return Object.keys(schema).every(key => key in value);
|
|
564
|
+
return Object.keys(schema).every((key) => key in value);
|
|
535
565
|
}
|
|
536
566
|
function hasReadabilityScore(text, minScore) {
|
|
537
567
|
// This is a simplified implementation
|
|
@@ -545,47 +575,50 @@ function syllables(word) {
|
|
|
545
575
|
word = word.toLowerCase();
|
|
546
576
|
if (word.length <= 3)
|
|
547
577
|
return 1;
|
|
548
|
-
return word
|
|
578
|
+
return word
|
|
579
|
+
.replace(/[^aeiouy]+/g, " ")
|
|
580
|
+
.trim()
|
|
581
|
+
.split(/\s+/).length;
|
|
549
582
|
}
|
|
550
583
|
function containsLanguage(text, language) {
|
|
551
584
|
// This is a simplified implementation
|
|
552
585
|
// In a real app, you'd use a language detection library
|
|
553
586
|
const languageKeywords = {
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
587
|
+
en: ["the", "and", "you", "that", "was", "for", "are", "with"],
|
|
588
|
+
es: ["el", "la", "los", "las", "de", "que", "y", "en"],
|
|
589
|
+
fr: ["le", "la", "les", "de", "et", "à", "un", "une"],
|
|
557
590
|
};
|
|
558
591
|
const keywords = languageKeywords[language.toLowerCase()] || [];
|
|
559
|
-
return keywords.some(keyword => text.toLowerCase().includes(keyword));
|
|
592
|
+
return keywords.some((keyword) => text.toLowerCase().includes(keyword));
|
|
560
593
|
}
|
|
561
594
|
function hasFactualAccuracy(text, facts) {
|
|
562
595
|
// This is a simplified implementation
|
|
563
|
-
return facts.every(fact => text.includes(fact));
|
|
596
|
+
return facts.every((fact) => text.includes(fact));
|
|
564
597
|
}
|
|
565
598
|
function respondedWithinTime(startTime, maxMs) {
|
|
566
599
|
return Date.now() - startTime <= maxMs;
|
|
567
600
|
}
|
|
568
601
|
function hasNoToxicity(text) {
|
|
569
602
|
// This is a simplified implementation
|
|
570
|
-
const toxicWords = [
|
|
571
|
-
return !toxicWords.some(word => text.toLowerCase().includes(word));
|
|
603
|
+
const toxicWords = ["hate", "stupid", "idiot", "dumb"];
|
|
604
|
+
return !toxicWords.some((word) => text.toLowerCase().includes(word));
|
|
572
605
|
}
|
|
573
606
|
function followsInstructions(text, instructions) {
|
|
574
|
-
return instructions.every(instruction => {
|
|
575
|
-
if (instruction.startsWith(
|
|
607
|
+
return instructions.every((instruction) => {
|
|
608
|
+
if (instruction.startsWith("!")) {
|
|
576
609
|
return !text.includes(instruction.slice(1));
|
|
577
610
|
}
|
|
578
611
|
return text.includes(instruction);
|
|
579
612
|
});
|
|
580
613
|
}
|
|
581
614
|
function containsAllRequiredFields(obj, requiredFields) {
|
|
582
|
-
return requiredFields.every(field => field in obj);
|
|
615
|
+
return requiredFields.every((field) => field in obj);
|
|
583
616
|
}
|
|
584
617
|
function hasValidCodeSyntax(code, language) {
|
|
585
618
|
// This is a simplified implementation
|
|
586
619
|
// In a real app, you'd use a proper parser for each language
|
|
587
620
|
try {
|
|
588
|
-
if (language ===
|
|
621
|
+
if (language === "json")
|
|
589
622
|
JSON.parse(code);
|
|
590
623
|
// Add more language validations as needed
|
|
591
624
|
return true;
|
package/dist/batch.js
CHANGED
|
@@ -57,7 +57,7 @@ class RequestBatcher {
|
|
|
57
57
|
*/
|
|
58
58
|
async processBatch() {
|
|
59
59
|
if (this.batchTimer) {
|
|
60
|
-
if (typeof this.batchTimer ===
|
|
60
|
+
if (typeof this.batchTimer === "number") {
|
|
61
61
|
clearTimeout(this.batchTimer);
|
|
62
62
|
}
|
|
63
63
|
else {
|
|
@@ -70,12 +70,12 @@ class RequestBatcher {
|
|
|
70
70
|
}
|
|
71
71
|
// Take items from queue
|
|
72
72
|
const batch = this.queue.splice(0, this.maxBatchSize);
|
|
73
|
-
const requests = batch.map(item => item.request);
|
|
73
|
+
const requests = batch.map((item) => item.request);
|
|
74
74
|
try {
|
|
75
75
|
const responses = await this.executeBatch(requests);
|
|
76
76
|
// Match responses to requests and resolve/reject
|
|
77
77
|
for (const response of responses) {
|
|
78
|
-
const pendingRequest = batch.find(item => item.id === response.id);
|
|
78
|
+
const pendingRequest = batch.find((item) => item.id === response.id);
|
|
79
79
|
if (pendingRequest) {
|
|
80
80
|
if (response.status >= 200 && response.status < 300) {
|
|
81
81
|
pendingRequest.resolve(response.data);
|
|
@@ -87,8 +87,8 @@ class RequestBatcher {
|
|
|
87
87
|
}
|
|
88
88
|
// Handle any requests that didn't get a response
|
|
89
89
|
for (const item of batch) {
|
|
90
|
-
if (!responses.find(r => r.id === item.id)) {
|
|
91
|
-
item.reject(new Error(
|
|
90
|
+
if (!responses.find((r) => r.id === item.id)) {
|
|
91
|
+
item.reject(new Error("No response received for request"));
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
}
|
|
@@ -116,7 +116,7 @@ class RequestBatcher {
|
|
|
116
116
|
*/
|
|
117
117
|
clear() {
|
|
118
118
|
if (this.batchTimer) {
|
|
119
|
-
if (typeof this.batchTimer ===
|
|
119
|
+
if (typeof this.batchTimer === "number") {
|
|
120
120
|
clearTimeout(this.batchTimer);
|
|
121
121
|
}
|
|
122
122
|
else {
|
|
@@ -126,7 +126,7 @@ class RequestBatcher {
|
|
|
126
126
|
}
|
|
127
127
|
// Reject all pending requests
|
|
128
128
|
for (const item of this.queue) {
|
|
129
|
-
item.reject(new Error(
|
|
129
|
+
item.reject(new Error("Batch queue cleared"));
|
|
130
130
|
}
|
|
131
131
|
this.queue = [];
|
|
132
132
|
}
|
|
@@ -146,16 +146,11 @@ exports.RequestBatcher = RequestBatcher;
|
|
|
146
146
|
* Check if requests can be batched together
|
|
147
147
|
*/
|
|
148
148
|
function canBatch(method, endpoint) {
|
|
149
|
-
if (method !==
|
|
149
|
+
if (method !== "GET") {
|
|
150
150
|
return false;
|
|
151
151
|
}
|
|
152
|
-
const batchableEndpoints = [
|
|
153
|
-
|
|
154
|
-
'/evaluations',
|
|
155
|
-
'/annotations',
|
|
156
|
-
'/results',
|
|
157
|
-
];
|
|
158
|
-
return batchableEndpoints.some(pattern => endpoint.includes(pattern));
|
|
152
|
+
const batchableEndpoints = ["/traces", "/evaluations", "/annotations", "/results"];
|
|
153
|
+
return batchableEndpoints.some((pattern) => endpoint.includes(pattern));
|
|
159
154
|
}
|
|
160
155
|
/**
|
|
161
156
|
* Batch multiple async operations with concurrency limit
|
|
@@ -164,13 +159,13 @@ async function batchProcess(items, processor, concurrency = 5) {
|
|
|
164
159
|
const results = [];
|
|
165
160
|
const executing = [];
|
|
166
161
|
for (const item of items) {
|
|
167
|
-
const promise = processor(item).then(result => {
|
|
162
|
+
const promise = processor(item).then((result) => {
|
|
168
163
|
results.push(result);
|
|
169
164
|
});
|
|
170
165
|
executing.push(promise);
|
|
171
166
|
if (executing.length >= concurrency) {
|
|
172
167
|
await Promise.race(executing);
|
|
173
|
-
executing.splice(executing.
|
|
168
|
+
executing.splice(executing.indexOf(promise), 1);
|
|
174
169
|
}
|
|
175
170
|
}
|
|
176
171
|
await Promise.all(executing);
|
package/dist/cache.js
CHANGED
|
@@ -16,7 +16,7 @@ class RequestCache {
|
|
|
16
16
|
* Generate cache key from request parameters
|
|
17
17
|
*/
|
|
18
18
|
generateKey(method, url, params) {
|
|
19
|
-
const paramString = params ? JSON.stringify(params) :
|
|
19
|
+
const paramString = params ? JSON.stringify(params) : "";
|
|
20
20
|
return `${method}:${url}:${paramString}`;
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
@@ -107,28 +107,24 @@ exports.CacheTTL = {
|
|
|
107
107
|
* Determine if a request should be cached based on method and endpoint
|
|
108
108
|
*/
|
|
109
109
|
function shouldCache(method, endpoint) {
|
|
110
|
-
if (method !==
|
|
110
|
+
if (method !== "GET") {
|
|
111
111
|
return false;
|
|
112
112
|
}
|
|
113
|
-
const noCacheEndpoints = [
|
|
114
|
-
|
|
115
|
-
'/usage',
|
|
116
|
-
'/deliveries',
|
|
117
|
-
];
|
|
118
|
-
return !noCacheEndpoints.some(pattern => endpoint.includes(pattern));
|
|
113
|
+
const noCacheEndpoints = ["/health", "/usage", "/deliveries"];
|
|
114
|
+
return !noCacheEndpoints.some((pattern) => endpoint.includes(pattern));
|
|
119
115
|
}
|
|
120
116
|
/**
|
|
121
117
|
* @internal - Internal SDK logic, not part of public API
|
|
122
118
|
* Get appropriate TTL for an endpoint
|
|
123
119
|
*/
|
|
124
120
|
function getTTL(endpoint) {
|
|
125
|
-
if (endpoint.includes(
|
|
121
|
+
if (endpoint.includes("/api-keys") || endpoint.includes("/webhooks")) {
|
|
126
122
|
return exports.CacheTTL.LONG;
|
|
127
123
|
}
|
|
128
|
-
if (endpoint.includes(
|
|
124
|
+
if (endpoint.includes("/evaluations") || endpoint.includes("/configs")) {
|
|
129
125
|
return exports.CacheTTL.MEDIUM;
|
|
130
126
|
}
|
|
131
|
-
if (endpoint.includes(
|
|
127
|
+
if (endpoint.includes("/traces") || endpoint.includes("/results")) {
|
|
132
128
|
return exports.CacheTTL.SHORT;
|
|
133
129
|
}
|
|
134
130
|
return exports.CacheTTL.MEDIUM;
|