@pauly4010/evalai-sdk 1.3.0 → 1.4.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/.env.example +0 -0
- package/ADDITIONAL_ISSUES_FOUND.md +174 -0
- package/README.md +75 -4
- package/dist/__tests__/assertions.test.d.ts +1 -0
- package/dist/__tests__/assertions.test.js +288 -0
- package/dist/__tests__/client.test.d.ts +1 -0
- package/dist/__tests__/client.test.js +185 -0
- package/dist/__tests__/testing.test.d.ts +1 -0
- package/dist/__tests__/testing.test.js +230 -0
- package/dist/__tests__/workflows.test.d.ts +1 -0
- package/dist/__tests__/workflows.test.js +222 -0
- package/dist/cli/check.d.ts +58 -0
- package/dist/cli/check.js +204 -0
- package/dist/cli/index.d.ts +4 -2
- package/dist/cli/index.js +38 -175
- package/dist/client.d.ts +14 -1
- package/dist/client.js +56 -6
- package/dist/index.d.ts +1 -0
- package/dist/index.js +6 -1
- package/dist/types.d.ts +8 -0
- package/dist/workflows.js +2 -7
- package/evalai-sdk-1.2.0.tgz +0 -0
- package/package.json +12 -27
- package/postcss.config.mjs +2 -0
- package/LICENSE +0 -21
package/.env.example
ADDED
|
Binary file
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# Additional Issues Found in Second Review
|
|
2
|
+
|
|
3
|
+
## 🔴 Issues Discovered
|
|
4
|
+
|
|
5
|
+
### 1. **process.env Usage in Browser Context** ⚠️ HIGH PRIORITY
|
|
6
|
+
|
|
7
|
+
**Files**: `client.ts` (lines 105, 116, 178)
|
|
8
|
+
|
|
9
|
+
**Problem**: The SDK uses `process.env` directly, which is undefined in browsers:
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
// Line 105
|
|
13
|
+
this.apiKey = config.apiKey || process.env.EVALAI_API_KEY || ...
|
|
14
|
+
|
|
15
|
+
// Line 116
|
|
16
|
+
const orgIdFromEnv = process.env.EVALAI_ORGANIZATION_ID || ...
|
|
17
|
+
|
|
18
|
+
// Line 178 (in static init method)
|
|
19
|
+
baseUrl: process.env.EVALAI_BASE_URL,
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Impact**:
|
|
23
|
+
- Will cause "Cannot read property of undefined" errors in browsers
|
|
24
|
+
- Breaks zero-config initialization in browsers
|
|
25
|
+
- `AIEvalClient.init()` won't work in browsers
|
|
26
|
+
|
|
27
|
+
**Severity**: HIGH - Core functionality breaks in browsers
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
### 2. **Type Name Collision** 🟡 MEDIUM PRIORITY
|
|
32
|
+
|
|
33
|
+
**Files**: `types.ts` (line 209) and `testing.ts` (line 27)
|
|
34
|
+
|
|
35
|
+
**Problem**: Two different `TestCase` interfaces with same name but different purposes:
|
|
36
|
+
|
|
37
|
+
**types.ts** (Database Model):
|
|
38
|
+
```typescript
|
|
39
|
+
export interface TestCase {
|
|
40
|
+
id: number;
|
|
41
|
+
evaluationId: number;
|
|
42
|
+
input: string;
|
|
43
|
+
expectedOutput: string | null;
|
|
44
|
+
metadata: Record<string, any> | null;
|
|
45
|
+
createdAt: string;
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**testing.ts** (Test Suite Model):
|
|
50
|
+
```typescript
|
|
51
|
+
export interface TestCase {
|
|
52
|
+
id?: string;
|
|
53
|
+
input: string;
|
|
54
|
+
expected?: string;
|
|
55
|
+
metadata?: Record<string, any>;
|
|
56
|
+
assertions?: ((output: string) => AssertionResult)[];
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Impact**:
|
|
61
|
+
- Confusing for developers
|
|
62
|
+
- IDE autocomplete shows wrong interface
|
|
63
|
+
- Only `types.ts` version is exported from index.ts (line 117)
|
|
64
|
+
- Could cause type errors if both are imported
|
|
65
|
+
|
|
66
|
+
**Severity**: MEDIUM - Causes confusion but only types.ts version is publicly exported
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
### 3. **Dynamic Import Pattern in export.ts** 🟢 LOW PRIORITY
|
|
71
|
+
|
|
72
|
+
**Files**: `export.ts` (lines 296, 316)
|
|
73
|
+
|
|
74
|
+
**Pattern**:
|
|
75
|
+
```typescript
|
|
76
|
+
const fs = await import('fs');
|
|
77
|
+
fs.writeFileSync(filePath, ...);
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Issue**:
|
|
81
|
+
- Dynamic import returns a module namespace object
|
|
82
|
+
- Works but is unusual pattern (normally use static imports in Node.js-only files)
|
|
83
|
+
- Could fail in some bundler configurations
|
|
84
|
+
|
|
85
|
+
**Impact**:
|
|
86
|
+
- Works but non-standard
|
|
87
|
+
- Tree-shaking friendly but unnecessary for Node.js-only code
|
|
88
|
+
- Some bundlers might have issues
|
|
89
|
+
|
|
90
|
+
**Severity**: LOW - Works but not best practice
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
### 4. **TypeScript Module Configuration** 🟢 INFO
|
|
95
|
+
|
|
96
|
+
**File**: `tsconfig.json`
|
|
97
|
+
|
|
98
|
+
**Current**:
|
|
99
|
+
```json
|
|
100
|
+
{
|
|
101
|
+
"module": "commonjs"
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Observation**:
|
|
106
|
+
- Using CommonJS but package.json has ES module exports
|
|
107
|
+
- CLI uses `.js` extensions in imports (which is correct for ES modules)
|
|
108
|
+
- Mismatch between TypeScript config and runtime expectations
|
|
109
|
+
|
|
110
|
+
**Impact**:
|
|
111
|
+
- May cause issues with module resolution
|
|
112
|
+
- CLI imports might not work as expected
|
|
113
|
+
- Bundlers might be confused
|
|
114
|
+
|
|
115
|
+
**Severity**: LOW - Currently working but could cause subtle issues
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## 📊 Summary
|
|
120
|
+
|
|
121
|
+
| Issue | Severity | Impact | Affected |
|
|
122
|
+
|-------|----------|--------|----------|
|
|
123
|
+
| process.env in browser | 🔴 HIGH | Breaks in browsers | Core client |
|
|
124
|
+
| TestCase collision | 🟡 MEDIUM | Developer confusion | Types |
|
|
125
|
+
| Dynamic imports | 🟢 LOW | Unusual pattern | export.ts |
|
|
126
|
+
| Module config | 🟢 INFO | Potential confusion | Build system |
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## ✅ Recommended Fixes
|
|
131
|
+
|
|
132
|
+
### Fix 1: Safe process.env Access
|
|
133
|
+
|
|
134
|
+
Add helper function:
|
|
135
|
+
```typescript
|
|
136
|
+
// utils.ts or client.ts
|
|
137
|
+
function getEnvVar(name: string): string | undefined {
|
|
138
|
+
if (typeof process !== 'undefined' && process.env) {
|
|
139
|
+
return process.env[name];
|
|
140
|
+
}
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Then use:
|
|
146
|
+
```typescript
|
|
147
|
+
this.apiKey = config.apiKey || getEnvVar('EVALAI_API_KEY') || ...
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Fix 2: Rename Test Suite TestCase
|
|
151
|
+
|
|
152
|
+
Rename in `testing.ts`:
|
|
153
|
+
```typescript
|
|
154
|
+
export interface TestSuiteCase { // Was: TestCase
|
|
155
|
+
id?: string;
|
|
156
|
+
input: string;
|
|
157
|
+
expected?: string;
|
|
158
|
+
// ...
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Fix 3: Static Imports in export.ts
|
|
163
|
+
|
|
164
|
+
Since already checked for Node.js environment:
|
|
165
|
+
```typescript
|
|
166
|
+
import * as fs from 'fs'; // Instead of: const fs = await import('fs')
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Fix 4: Consider ES Modules
|
|
170
|
+
|
|
171
|
+
Either:
|
|
172
|
+
- Change tsconfig to `"module": "es2020"`
|
|
173
|
+
- Or change package.json exports to use `.cjs` extensions
|
|
174
|
+
|
package/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# @pauly4010/evalai-sdk
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@pauly4010/evalai-sdk)
|
|
4
|
+
[](https://www.npmjs.com/package/@pauly4010/evalai-sdk)
|
|
5
|
+
|
|
3
6
|
Official TypeScript/JavaScript SDK for the AI Evaluation Platform. Build confidence in your AI systems with comprehensive evaluation tools.
|
|
4
7
|
|
|
5
8
|
## Installation
|
|
@@ -498,9 +501,78 @@ console.log("Plan:", org.plan);
|
|
|
498
501
|
console.log("Status:", org.status);
|
|
499
502
|
```
|
|
500
503
|
|
|
504
|
+
## evalai CLI (v1.4.0)
|
|
505
|
+
|
|
506
|
+
The SDK includes a CLI for CI/CD evaluation gates. Install globally or use via `npx`:
|
|
507
|
+
|
|
508
|
+
```bash
|
|
509
|
+
# Via npx (no global install)
|
|
510
|
+
npx @pauly4010/evalai-sdk check --minScore 92 --evaluationId 42 --apiKey $EVALAI_API_KEY
|
|
511
|
+
|
|
512
|
+
# Or install globally
|
|
513
|
+
npm install -g @pauly4010/evalai-sdk
|
|
514
|
+
evalai check --minScore 92 --evaluationId 42
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
### evalai check
|
|
518
|
+
|
|
519
|
+
Gate deployments on quality scores, regression, and compliance:
|
|
520
|
+
|
|
521
|
+
| Option | Description |
|
|
522
|
+
|--------|-------------|
|
|
523
|
+
| `--evaluationId <id>` | **Required.** Evaluation to gate on |
|
|
524
|
+
| `--apiKey <key>` | API key (or `EVALAI_API_KEY` env) |
|
|
525
|
+
| `--minScore <n>` | Fail if score < n (0–100) |
|
|
526
|
+
| `--maxDrop <n>` | Fail if score dropped > n from baseline |
|
|
527
|
+
| `--minN <n>` | Fail if total test cases < n |
|
|
528
|
+
| `--allowWeakEvidence` | Permit weak evidence level |
|
|
529
|
+
| `--policy <name>` | Enforce HIPAA, SOC2, GDPR, PCI_DSS, FINRA_4511 |
|
|
530
|
+
| `--baseline <mode>` | `published` or `previous` |
|
|
531
|
+
| `--baseUrl <url>` | API base URL |
|
|
532
|
+
|
|
533
|
+
**Exit codes:** 0=pass, 1=score below, 2=regression, 3=policy violation, 4=API error, 5=bad args, 6=low N, 7=weak evidence
|
|
534
|
+
|
|
501
535
|
## Changelog
|
|
502
536
|
|
|
503
|
-
### v1.
|
|
537
|
+
### v1.4.0 (Latest)
|
|
538
|
+
|
|
539
|
+
- **evalai CLI** — Command-line tool for CI/CD evaluation gates
|
|
540
|
+
- `evalai check` — Gate deployments on quality scores, regression, and compliance
|
|
541
|
+
- `--minScore <n>` — Fail if quality score < n (0–100)
|
|
542
|
+
- `--maxDrop <n>` — Fail if score dropped > n points from baseline
|
|
543
|
+
- `--minN <n>` — Fail if total test cases < n
|
|
544
|
+
- `--allowWeakEvidence` — Permit weak evidence level (default: fail)
|
|
545
|
+
- `--policy <name>` — Enforce compliance (HIPAA, SOC2, GDPR, PCI_DSS, FINRA_4511)
|
|
546
|
+
- `--baseline <mode>` — Compare to `published` or `previous` run
|
|
547
|
+
- `--evaluationId <id>` — Required. Evaluation to gate on
|
|
548
|
+
- Environment: `EVALAI_API_KEY`, `EVALAI_BASE_URL`
|
|
549
|
+
- Exit codes: 0=pass, 1=score below, 2=regression, 3=policy violation, 4=API error, 5=bad args, 6=low N, 7=weak evidence
|
|
550
|
+
- **CLI Exports** — `parseArgs`, `runCheck`, `EXIT` from `@pauly4010/evalai-sdk` for programmatic use
|
|
551
|
+
|
|
552
|
+
### v1.3.0
|
|
553
|
+
|
|
554
|
+
- **Workflow Tracing** — Multi-agent orchestration with full lifecycle instrumentation
|
|
555
|
+
- `WorkflowTracer` class with `startWorkflow`, `endWorkflow`, `startAgentSpan`, `endAgentSpan`
|
|
556
|
+
- `createWorkflowTracer` convenience factory
|
|
557
|
+
- `traceWorkflowStep` generic wrapper for any async function
|
|
558
|
+
- Agent handoff recording (`delegation`, `escalation`, `parallel`, `fallback`)
|
|
559
|
+
- Decision auditing with alternatives, confidence scores, reasoning, and context factors
|
|
560
|
+
- Cost tracking per span/workflow with automatic pricing (16+ models)
|
|
561
|
+
- Cost breakdown by category (`llm`, `tool`, `embedding`, `other`)
|
|
562
|
+
- **Framework Integrations** — Wrap popular multi-agent frameworks:
|
|
563
|
+
- `traceLangChainAgent` — wraps `.invoke()` and `.call()` with auto-tracing
|
|
564
|
+
- `traceCrewAI` — wraps `.kickoff()` with workflow start/end
|
|
565
|
+
- `traceAutoGen` — wraps `.initiate_chat()` with workflow start/end
|
|
566
|
+
- **Performance Utilities**
|
|
567
|
+
- `RequestCache` with configurable TTL (`CacheTTL` presets)
|
|
568
|
+
- `PaginatedIterator` / `createPaginatedIterator` / `autoPaginate` for cursor-based pagination
|
|
569
|
+
- `RequestBatcher` for batching API calls
|
|
570
|
+
- `RateLimiter` client-side rate limit handling
|
|
571
|
+
- **Cost Tracking Types** — `CostRecord`, `CostBreakdown`, `ProviderPricing` interfaces
|
|
572
|
+
- **Agent Decision Auditing Types** — `AgentDecision`, `DecisionAlternative`, `RecordDecisionParams` interfaces
|
|
573
|
+
- **Benchmark Types** — `Benchmark`, `BenchmarkResult`, `AgentConfig` interfaces
|
|
574
|
+
|
|
575
|
+
### v1.2.1 (Bug Fixes)
|
|
504
576
|
|
|
505
577
|
- 🐛 **Critical Fixes**
|
|
506
578
|
- Fixed CLI import paths for proper npm package distribution
|
|
@@ -560,6 +632,5 @@ MIT
|
|
|
560
632
|
|
|
561
633
|
## Support
|
|
562
634
|
|
|
563
|
-
- Documentation: https://
|
|
564
|
-
- Issues: https://github.com/
|
|
565
|
-
- Discord: https://discord.gg/evalai
|
|
635
|
+
- Documentation: https://v0-ai-evaluation-platform-nu.vercel.app/documentation
|
|
636
|
+
- Issues: https://github.com/pauly7610/ai-evaluation-platform/issues
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const assertions_1 = require("../assertions");
|
|
5
|
+
(0, vitest_1.describe)('Expectation fluent API', () => {
|
|
6
|
+
(0, vitest_1.describe)('toEqual', () => {
|
|
7
|
+
(0, vitest_1.it)('should pass when values are equal', () => {
|
|
8
|
+
const result = (0, assertions_1.expect)('hello').toEqual('hello');
|
|
9
|
+
(0, vitest_1.expect)(result.passed).toBe(true);
|
|
10
|
+
(0, vitest_1.expect)(result.name).toBe('toEqual');
|
|
11
|
+
});
|
|
12
|
+
(0, vitest_1.it)('should fail when values differ', () => {
|
|
13
|
+
const result = (0, assertions_1.expect)('hello').toEqual('world');
|
|
14
|
+
(0, vitest_1.expect)(result.passed).toBe(false);
|
|
15
|
+
});
|
|
16
|
+
(0, vitest_1.it)('should handle objects', () => {
|
|
17
|
+
const result = (0, assertions_1.expect)({ a: 1 }).toEqual({ a: 1 });
|
|
18
|
+
(0, vitest_1.expect)(result.passed).toBe(true);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
(0, vitest_1.describe)('toContain', () => {
|
|
22
|
+
(0, vitest_1.it)('should pass when substring is found', () => {
|
|
23
|
+
const result = (0, assertions_1.expect)('Hello, world!').toContain('world');
|
|
24
|
+
(0, vitest_1.expect)(result.passed).toBe(true);
|
|
25
|
+
});
|
|
26
|
+
(0, vitest_1.it)('should fail when substring is missing', () => {
|
|
27
|
+
const result = (0, assertions_1.expect)('Hello, world!').toContain('foo');
|
|
28
|
+
(0, vitest_1.expect)(result.passed).toBe(false);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
(0, vitest_1.describe)('toContainKeywords', () => {
|
|
32
|
+
(0, vitest_1.it)('should pass when all keywords are present (case insensitive)', () => {
|
|
33
|
+
const result = (0, assertions_1.expect)('The quick Brown fox').toContainKeywords(['quick', 'brown']);
|
|
34
|
+
(0, vitest_1.expect)(result.passed).toBe(true);
|
|
35
|
+
});
|
|
36
|
+
(0, vitest_1.it)('should fail when keywords are missing', () => {
|
|
37
|
+
const result = (0, assertions_1.expect)('The quick fox').toContainKeywords(['quick', 'brown']);
|
|
38
|
+
(0, vitest_1.expect)(result.passed).toBe(false);
|
|
39
|
+
(0, vitest_1.expect)(result.message).toContain('brown');
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
(0, vitest_1.describe)('toNotContain', () => {
|
|
43
|
+
(0, vitest_1.it)('should pass when substring is absent', () => {
|
|
44
|
+
const result = (0, assertions_1.expect)('safe text').toNotContain('danger');
|
|
45
|
+
(0, vitest_1.expect)(result.passed).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
(0, vitest_1.it)('should fail when substring is present', () => {
|
|
48
|
+
const result = (0, assertions_1.expect)('some danger ahead').toNotContain('danger');
|
|
49
|
+
(0, vitest_1.expect)(result.passed).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
(0, vitest_1.describe)('toNotContainPII', () => {
|
|
53
|
+
(0, vitest_1.it)('should pass with no PII', () => {
|
|
54
|
+
const result = (0, assertions_1.expect)('Just a normal sentence').toNotContainPII();
|
|
55
|
+
(0, vitest_1.expect)(result.passed).toBe(true);
|
|
56
|
+
});
|
|
57
|
+
(0, vitest_1.it)('should fail with an email', () => {
|
|
58
|
+
const result = (0, assertions_1.expect)('Contact me at user@example.com').toNotContainPII();
|
|
59
|
+
(0, vitest_1.expect)(result.passed).toBe(false);
|
|
60
|
+
});
|
|
61
|
+
(0, vitest_1.it)('should fail with a phone number', () => {
|
|
62
|
+
const result = (0, assertions_1.expect)('Call 555-123-4567').toNotContainPII();
|
|
63
|
+
(0, vitest_1.expect)(result.passed).toBe(false);
|
|
64
|
+
});
|
|
65
|
+
(0, vitest_1.it)('should fail with an SSN', () => {
|
|
66
|
+
const result = (0, assertions_1.expect)('SSN is 123-45-6789').toNotContainPII();
|
|
67
|
+
(0, vitest_1.expect)(result.passed).toBe(false);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
(0, vitest_1.describe)('toMatchPattern', () => {
|
|
71
|
+
(0, vitest_1.it)('should pass when pattern matches', () => {
|
|
72
|
+
const result = (0, assertions_1.expect)('Order #12345').toMatchPattern(/Order #\d+/);
|
|
73
|
+
(0, vitest_1.expect)(result.passed).toBe(true);
|
|
74
|
+
});
|
|
75
|
+
(0, vitest_1.it)('should fail when pattern does not match', () => {
|
|
76
|
+
const result = (0, assertions_1.expect)('No order here').toMatchPattern(/Order #\d+/);
|
|
77
|
+
(0, vitest_1.expect)(result.passed).toBe(false);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
(0, vitest_1.describe)('toBeValidJSON', () => {
|
|
81
|
+
(0, vitest_1.it)('should pass for valid JSON', () => {
|
|
82
|
+
const result = (0, assertions_1.expect)('{"key": "value"}').toBeValidJSON();
|
|
83
|
+
(0, vitest_1.expect)(result.passed).toBe(true);
|
|
84
|
+
});
|
|
85
|
+
(0, vitest_1.it)('should fail for invalid JSON', () => {
|
|
86
|
+
const result = (0, assertions_1.expect)('not json').toBeValidJSON();
|
|
87
|
+
(0, vitest_1.expect)(result.passed).toBe(false);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
(0, vitest_1.describe)('toMatchJSON', () => {
|
|
91
|
+
(0, vitest_1.it)('should pass when all schema keys exist', () => {
|
|
92
|
+
const result = (0, assertions_1.expect)('{"status":"ok","data":1}').toMatchJSON({ status: '', data: '' });
|
|
93
|
+
(0, vitest_1.expect)(result.passed).toBe(true);
|
|
94
|
+
});
|
|
95
|
+
(0, vitest_1.it)('should fail when schema keys are missing', () => {
|
|
96
|
+
const result = (0, assertions_1.expect)('{"status":"ok"}').toMatchJSON({ status: '', missing: '' });
|
|
97
|
+
(0, vitest_1.expect)(result.passed).toBe(false);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
(0, vitest_1.describe)('toHaveSentiment', () => {
|
|
101
|
+
(0, vitest_1.it)('should detect positive sentiment', () => {
|
|
102
|
+
const result = (0, assertions_1.expect)('This is great and amazing!').toHaveSentiment('positive');
|
|
103
|
+
(0, vitest_1.expect)(result.passed).toBe(true);
|
|
104
|
+
});
|
|
105
|
+
(0, vitest_1.it)('should detect negative sentiment', () => {
|
|
106
|
+
const result = (0, assertions_1.expect)('This is terrible and awful').toHaveSentiment('negative');
|
|
107
|
+
(0, vitest_1.expect)(result.passed).toBe(true);
|
|
108
|
+
});
|
|
109
|
+
(0, vitest_1.it)('should detect neutral sentiment', () => {
|
|
110
|
+
const result = (0, assertions_1.expect)('The sky is blue').toHaveSentiment('neutral');
|
|
111
|
+
(0, vitest_1.expect)(result.passed).toBe(true);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
(0, vitest_1.describe)('toHaveLength', () => {
|
|
115
|
+
(0, vitest_1.it)('should pass when within range', () => {
|
|
116
|
+
const result = (0, assertions_1.expect)('hello').toHaveLength({ min: 3, max: 10 });
|
|
117
|
+
(0, vitest_1.expect)(result.passed).toBe(true);
|
|
118
|
+
});
|
|
119
|
+
(0, vitest_1.it)('should fail when too short', () => {
|
|
120
|
+
const result = (0, assertions_1.expect)('hi').toHaveLength({ min: 5 });
|
|
121
|
+
(0, vitest_1.expect)(result.passed).toBe(false);
|
|
122
|
+
});
|
|
123
|
+
(0, vitest_1.it)('should fail when too long', () => {
|
|
124
|
+
const result = (0, assertions_1.expect)('a very long string').toHaveLength({ max: 5 });
|
|
125
|
+
(0, vitest_1.expect)(result.passed).toBe(false);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
(0, vitest_1.describe)('toNotHallucinate', () => {
|
|
129
|
+
(0, vitest_1.it)('should pass when all facts are present', () => {
|
|
130
|
+
const result = (0, assertions_1.expect)('Paris is the capital of France').toNotHallucinate(['paris', 'france']);
|
|
131
|
+
(0, vitest_1.expect)(result.passed).toBe(true);
|
|
132
|
+
});
|
|
133
|
+
(0, vitest_1.it)('should fail when facts are missing', () => {
|
|
134
|
+
const result = (0, assertions_1.expect)('Berlin is great').toNotHallucinate(['paris', 'france']);
|
|
135
|
+
(0, vitest_1.expect)(result.passed).toBe(false);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
(0, vitest_1.describe)('toBeFasterThan', () => {
|
|
139
|
+
(0, vitest_1.it)('should pass when value is under threshold', () => {
|
|
140
|
+
const result = (0, assertions_1.expect)(500).toBeFasterThan(1000);
|
|
141
|
+
(0, vitest_1.expect)(result.passed).toBe(true);
|
|
142
|
+
});
|
|
143
|
+
(0, vitest_1.it)('should fail when value exceeds threshold', () => {
|
|
144
|
+
const result = (0, assertions_1.expect)(1500).toBeFasterThan(1000);
|
|
145
|
+
(0, vitest_1.expect)(result.passed).toBe(false);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
(0, vitest_1.describe)('toBeTruthy / toBeFalsy', () => {
|
|
149
|
+
(0, vitest_1.it)('should pass for truthy values', () => {
|
|
150
|
+
(0, vitest_1.expect)((0, assertions_1.expect)('hello').toBeTruthy().passed).toBe(true);
|
|
151
|
+
(0, vitest_1.expect)((0, assertions_1.expect)(1).toBeTruthy().passed).toBe(true);
|
|
152
|
+
});
|
|
153
|
+
(0, vitest_1.it)('should pass for falsy values', () => {
|
|
154
|
+
(0, vitest_1.expect)((0, assertions_1.expect)('').toBeFalsy().passed).toBe(true);
|
|
155
|
+
(0, vitest_1.expect)((0, assertions_1.expect)(0).toBeFalsy().passed).toBe(true);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
(0, vitest_1.describe)('toBeGreaterThan / toBeLessThan / toBeBetween', () => {
|
|
159
|
+
(0, vitest_1.it)('should work for greater than', () => {
|
|
160
|
+
(0, vitest_1.expect)((0, assertions_1.expect)(10).toBeGreaterThan(5).passed).toBe(true);
|
|
161
|
+
(0, vitest_1.expect)((0, assertions_1.expect)(3).toBeGreaterThan(5).passed).toBe(false);
|
|
162
|
+
});
|
|
163
|
+
(0, vitest_1.it)('should work for less than', () => {
|
|
164
|
+
(0, vitest_1.expect)((0, assertions_1.expect)(3).toBeLessThan(5).passed).toBe(true);
|
|
165
|
+
(0, vitest_1.expect)((0, assertions_1.expect)(10).toBeLessThan(5).passed).toBe(false);
|
|
166
|
+
});
|
|
167
|
+
(0, vitest_1.it)('should work for between', () => {
|
|
168
|
+
(0, vitest_1.expect)((0, assertions_1.expect)(5).toBeBetween(1, 10).passed).toBe(true);
|
|
169
|
+
(0, vitest_1.expect)((0, assertions_1.expect)(15).toBeBetween(1, 10).passed).toBe(false);
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
(0, vitest_1.describe)('toContainCode', () => {
|
|
173
|
+
(0, vitest_1.it)('should detect code blocks', () => {
|
|
174
|
+
const result = (0, assertions_1.expect)('Here is code:\n```js\nconsole.log("hi")\n```').toContainCode();
|
|
175
|
+
(0, vitest_1.expect)(result.passed).toBe(true);
|
|
176
|
+
});
|
|
177
|
+
(0, vitest_1.it)('should fail without code blocks', () => {
|
|
178
|
+
const result = (0, assertions_1.expect)('No code here').toContainCode();
|
|
179
|
+
(0, vitest_1.expect)(result.passed).toBe(false);
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
(0, vitest_1.describe)('toBeProfessional', () => {
|
|
183
|
+
(0, vitest_1.it)('should pass for professional text', () => {
|
|
184
|
+
const result = (0, assertions_1.expect)('Thank you for your inquiry.').toBeProfessional();
|
|
185
|
+
(0, vitest_1.expect)(result.passed).toBe(true);
|
|
186
|
+
});
|
|
187
|
+
(0, vitest_1.it)('should fail for unprofessional text', () => {
|
|
188
|
+
const result = (0, assertions_1.expect)('This is damn stupid').toBeProfessional();
|
|
189
|
+
(0, vitest_1.expect)(result.passed).toBe(false);
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
(0, vitest_1.describe)('toHaveProperGrammar', () => {
|
|
193
|
+
(0, vitest_1.it)('should pass for properly formatted text', () => {
|
|
194
|
+
const result = (0, assertions_1.expect)('This is a sentence.').toHaveProperGrammar();
|
|
195
|
+
(0, vitest_1.expect)(result.passed).toBe(true);
|
|
196
|
+
});
|
|
197
|
+
(0, vitest_1.it)('should fail for double spaces', () => {
|
|
198
|
+
const result = (0, assertions_1.expect)('This has double spaces.').toHaveProperGrammar();
|
|
199
|
+
(0, vitest_1.expect)(result.passed).toBe(false);
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
(0, vitest_1.describe)('runAssertions', () => {
|
|
204
|
+
(0, vitest_1.it)('should collect all results', () => {
|
|
205
|
+
const results = (0, assertions_1.runAssertions)([
|
|
206
|
+
() => (0, assertions_1.expect)('hello').toContain('hello'),
|
|
207
|
+
() => (0, assertions_1.expect)('hello').toContain('missing'),
|
|
208
|
+
]);
|
|
209
|
+
(0, vitest_1.expect)(results).toHaveLength(2);
|
|
210
|
+
(0, vitest_1.expect)(results[0].passed).toBe(true);
|
|
211
|
+
(0, vitest_1.expect)(results[1].passed).toBe(false);
|
|
212
|
+
});
|
|
213
|
+
(0, vitest_1.it)('should catch thrown errors', () => {
|
|
214
|
+
const results = (0, assertions_1.runAssertions)([
|
|
215
|
+
() => { throw new Error('boom'); },
|
|
216
|
+
]);
|
|
217
|
+
(0, vitest_1.expect)(results[0].passed).toBe(false);
|
|
218
|
+
(0, vitest_1.expect)(results[0].message).toBe('boom');
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
(0, vitest_1.describe)('Standalone assertion functions', () => {
|
|
222
|
+
(0, vitest_1.it)('containsKeywords', () => {
|
|
223
|
+
(0, vitest_1.expect)((0, assertions_1.containsKeywords)('The quick brown fox', ['quick', 'brown'])).toBe(true);
|
|
224
|
+
(0, vitest_1.expect)((0, assertions_1.containsKeywords)('The quick fox', ['quick', 'brown'])).toBe(false);
|
|
225
|
+
});
|
|
226
|
+
(0, vitest_1.it)('matchesPattern', () => {
|
|
227
|
+
(0, vitest_1.expect)((0, assertions_1.matchesPattern)('abc123', /\d+/)).toBe(true);
|
|
228
|
+
(0, vitest_1.expect)((0, assertions_1.matchesPattern)('abc', /\d+/)).toBe(false);
|
|
229
|
+
});
|
|
230
|
+
(0, vitest_1.it)('hasLength', () => {
|
|
231
|
+
(0, vitest_1.expect)((0, assertions_1.hasLength)('hello', { min: 3, max: 10 })).toBe(true);
|
|
232
|
+
(0, vitest_1.expect)((0, assertions_1.hasLength)('hi', { min: 5 })).toBe(false);
|
|
233
|
+
});
|
|
234
|
+
(0, vitest_1.it)('containsJSON', () => {
|
|
235
|
+
(0, vitest_1.expect)((0, assertions_1.containsJSON)('{"a":1}')).toBe(true);
|
|
236
|
+
(0, vitest_1.expect)((0, assertions_1.containsJSON)('not json')).toBe(false);
|
|
237
|
+
});
|
|
238
|
+
(0, vitest_1.it)('notContainsPII', () => {
|
|
239
|
+
(0, vitest_1.expect)((0, assertions_1.notContainsPII)('Just a normal text')).toBe(true);
|
|
240
|
+
(0, vitest_1.expect)((0, assertions_1.notContainsPII)('Email: user@example.com')).toBe(false);
|
|
241
|
+
});
|
|
242
|
+
(0, vitest_1.it)('hasSentiment', () => {
|
|
243
|
+
(0, vitest_1.expect)((0, assertions_1.hasSentiment)('This is great', 'positive')).toBe(true);
|
|
244
|
+
(0, vitest_1.expect)((0, assertions_1.hasSentiment)('This is terrible', 'negative')).toBe(true);
|
|
245
|
+
});
|
|
246
|
+
(0, vitest_1.it)('similarTo', () => {
|
|
247
|
+
(0, vitest_1.expect)((0, assertions_1.similarTo)('the quick brown fox', 'the quick brown dog', 0.5)).toBe(true);
|
|
248
|
+
(0, vitest_1.expect)((0, assertions_1.similarTo)('hello world', 'completely different', 0.8)).toBe(false);
|
|
249
|
+
});
|
|
250
|
+
(0, vitest_1.it)('withinRange', () => {
|
|
251
|
+
(0, vitest_1.expect)((0, assertions_1.withinRange)(5, 1, 10)).toBe(true);
|
|
252
|
+
(0, vitest_1.expect)((0, assertions_1.withinRange)(15, 1, 10)).toBe(false);
|
|
253
|
+
});
|
|
254
|
+
(0, vitest_1.it)('isValidEmail', () => {
|
|
255
|
+
(0, vitest_1.expect)((0, assertions_1.isValidEmail)('user@example.com')).toBe(true);
|
|
256
|
+
(0, vitest_1.expect)((0, assertions_1.isValidEmail)('not-an-email')).toBe(false);
|
|
257
|
+
});
|
|
258
|
+
(0, vitest_1.it)('isValidURL', () => {
|
|
259
|
+
(0, vitest_1.expect)((0, assertions_1.isValidURL)('https://example.com')).toBe(true);
|
|
260
|
+
(0, vitest_1.expect)((0, assertions_1.isValidURL)('not a url')).toBe(false);
|
|
261
|
+
});
|
|
262
|
+
(0, vitest_1.it)('hasNoHallucinations', () => {
|
|
263
|
+
(0, vitest_1.expect)((0, assertions_1.hasNoHallucinations)('Paris is in France', ['Paris', 'France'])).toBe(true);
|
|
264
|
+
(0, vitest_1.expect)((0, assertions_1.hasNoHallucinations)('Berlin is great', ['Paris'])).toBe(false);
|
|
265
|
+
});
|
|
266
|
+
(0, vitest_1.it)('matchesSchema', () => {
|
|
267
|
+
(0, vitest_1.expect)((0, assertions_1.matchesSchema)({ name: 'test', value: 1 }, { name: '', value: '' })).toBe(true);
|
|
268
|
+
(0, vitest_1.expect)((0, assertions_1.matchesSchema)({ name: 'test' }, { name: '', missing: '' })).toBe(false);
|
|
269
|
+
(0, vitest_1.expect)((0, assertions_1.matchesSchema)('not an object', { key: '' })).toBe(false);
|
|
270
|
+
});
|
|
271
|
+
(0, vitest_1.it)('hasNoToxicity', () => {
|
|
272
|
+
(0, vitest_1.expect)((0, assertions_1.hasNoToxicity)('Have a nice day')).toBe(true);
|
|
273
|
+
(0, vitest_1.expect)((0, assertions_1.hasNoToxicity)('You are an idiot')).toBe(false);
|
|
274
|
+
});
|
|
275
|
+
(0, vitest_1.it)('followsInstructions', () => {
|
|
276
|
+
(0, vitest_1.expect)((0, assertions_1.followsInstructions)('Hello world', ['Hello'])).toBe(true);
|
|
277
|
+
(0, vitest_1.expect)((0, assertions_1.followsInstructions)('Hello world', ['!goodbye'])).toBe(true);
|
|
278
|
+
(0, vitest_1.expect)((0, assertions_1.followsInstructions)('Hello world', ['missing'])).toBe(false);
|
|
279
|
+
});
|
|
280
|
+
(0, vitest_1.it)('containsAllRequiredFields', () => {
|
|
281
|
+
(0, vitest_1.expect)((0, assertions_1.containsAllRequiredFields)({ a: 1, b: 2 }, ['a', 'b'])).toBe(true);
|
|
282
|
+
(0, vitest_1.expect)((0, assertions_1.containsAllRequiredFields)({ a: 1 }, ['a', 'b'])).toBe(false);
|
|
283
|
+
});
|
|
284
|
+
(0, vitest_1.it)('hasValidCodeSyntax', () => {
|
|
285
|
+
(0, vitest_1.expect)((0, assertions_1.hasValidCodeSyntax)('{"valid": true}', 'json')).toBe(true);
|
|
286
|
+
(0, vitest_1.expect)((0, assertions_1.hasValidCodeSyntax)('{invalid}', 'json')).toBe(false);
|
|
287
|
+
});
|
|
288
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|