jest-fuzzy 0.1.0 → 0.1.1
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/README.md +69 -46
- package/dist/cjs/config.d.ts +5 -2
- package/dist/cjs/config.d.ts.map +1 -1
- package/dist/cjs/config.js +4 -1
- package/dist/cjs/config.js.map +1 -1
- package/dist/cjs/index.d.ts +2 -2
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/providers/anthropic.d.ts +2 -2
- package/dist/cjs/providers/anthropic.d.ts.map +1 -1
- package/dist/cjs/providers/anthropic.js +45 -73
- package/dist/cjs/providers/anthropic.js.map +1 -1
- package/dist/cjs/providers/google.d.ts +2 -2
- package/dist/cjs/providers/google.d.ts.map +1 -1
- package/dist/cjs/providers/google.js +50 -75
- package/dist/cjs/providers/google.js.map +1 -1
- package/dist/cjs/providers/index.d.ts +2 -2
- package/dist/cjs/providers/index.d.ts.map +1 -1
- package/dist/cjs/providers/index.js +4 -4
- package/dist/cjs/providers/index.js.map +1 -1
- package/dist/cjs/providers/openai.d.ts +2 -2
- package/dist/cjs/providers/openai.d.ts.map +1 -1
- package/dist/cjs/providers/openai.js +37 -58
- package/dist/cjs/providers/openai.js.map +1 -1
- package/dist/cjs/types.d.ts +6 -0
- package/dist/cjs/types.d.ts.map +1 -1
- package/dist/esm/config.d.ts +5 -2
- package/dist/esm/config.d.ts.map +1 -1
- package/dist/esm/config.js +4 -1
- package/dist/esm/config.js.map +1 -1
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/providers/anthropic.d.ts +2 -2
- package/dist/esm/providers/anthropic.d.ts.map +1 -1
- package/dist/esm/providers/anthropic.js +45 -40
- package/dist/esm/providers/anthropic.js.map +1 -1
- package/dist/esm/providers/google.d.ts +2 -2
- package/dist/esm/providers/google.d.ts.map +1 -1
- package/dist/esm/providers/google.js +50 -42
- package/dist/esm/providers/google.js.map +1 -1
- package/dist/esm/providers/index.d.ts +2 -2
- package/dist/esm/providers/index.d.ts.map +1 -1
- package/dist/esm/providers/index.js +4 -4
- package/dist/esm/providers/index.js.map +1 -1
- package/dist/esm/providers/openai.d.ts +2 -2
- package/dist/esm/providers/openai.d.ts.map +1 -1
- package/dist/esm/providers/openai.js +37 -25
- package/dist/esm/providers/openai.js.map +1 -1
- package/dist/esm/types.d.ts +6 -0
- package/dist/esm/types.d.ts.map +1 -1
- package/package.json +1 -20
package/README.md
CHANGED
|
@@ -23,48 +23,39 @@ await expect(response).toSemanticallyMatch("Hi, how may I assist you?");
|
|
|
23
23
|
npm install jest-fuzzy --save-dev
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
# For Claude (default)
|
|
30
|
-
npm install @anthropic-ai/sdk
|
|
31
|
-
|
|
32
|
-
# For Gemini
|
|
33
|
-
npm install @google/generative-ai
|
|
34
|
-
|
|
35
|
-
# For OpenAI
|
|
36
|
-
npm install openai
|
|
37
|
-
```
|
|
26
|
+
That's it! No additional dependencies required. jest-fuzzy uses Anthropic, OpenAI, and Google REST APIs directly.
|
|
38
27
|
|
|
39
28
|
## Quick Start
|
|
40
29
|
|
|
41
|
-
**1.
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
export ANTHROPIC_API_KEY=your-key-here
|
|
45
|
-
# or GOOGLE_API_KEY for Gemini
|
|
46
|
-
# or OPENAI_API_KEY for OpenAI
|
|
47
|
-
```
|
|
30
|
+
**1. Configure your API key (choose one method):**
|
|
48
31
|
|
|
49
|
-
|
|
32
|
+
Option A: Pass it directly (recommended for simplicity):
|
|
50
33
|
|
|
51
34
|
```typescript
|
|
52
35
|
// jest.setup.ts
|
|
53
36
|
import { configure } from "jest-fuzzy";
|
|
54
37
|
|
|
55
38
|
configure({
|
|
56
|
-
|
|
39
|
+
apiKeys: {
|
|
40
|
+
anthropic: "your-api-key-here",
|
|
41
|
+
},
|
|
57
42
|
});
|
|
58
43
|
```
|
|
59
44
|
|
|
60
|
-
|
|
45
|
+
Option B: Use environment variables:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
export ANTHROPIC_API_KEY=your-key-here
|
|
49
|
+
# or GOOGLE_API_KEY for Gemini
|
|
50
|
+
# or OPENAI_API_KEY for OpenAI
|
|
51
|
+
```
|
|
61
52
|
|
|
62
53
|
```typescript
|
|
63
54
|
// jest.setup.ts
|
|
64
55
|
import "jest-fuzzy";
|
|
65
56
|
```
|
|
66
57
|
|
|
67
|
-
**
|
|
58
|
+
**2. Reference the setup file in your Jest config:**
|
|
68
59
|
|
|
69
60
|
```javascript
|
|
70
61
|
// jest.config.js
|
|
@@ -73,7 +64,7 @@ module.exports = {
|
|
|
73
64
|
};
|
|
74
65
|
```
|
|
75
66
|
|
|
76
|
-
**
|
|
67
|
+
**3. Use the matchers in your tests:**
|
|
77
68
|
|
|
78
69
|
```typescript
|
|
79
70
|
describe("chatbot", () => {
|
|
@@ -93,19 +84,28 @@ describe("chatbot", () => {
|
|
|
93
84
|
|
|
94
85
|
### `configure(options?)`
|
|
95
86
|
|
|
96
|
-
Configures jest-fuzzy with your preferred model.
|
|
87
|
+
Configures jest-fuzzy with your preferred model and API keys.
|
|
97
88
|
|
|
98
89
|
```typescript
|
|
99
90
|
import { configure } from "jest-fuzzy";
|
|
100
91
|
|
|
101
92
|
configure({
|
|
102
93
|
model: "claude-haiku-4-5", // or "gemini-3-flash-preview" or "gpt-5-nano"
|
|
94
|
+
apiKeys: {
|
|
95
|
+
anthropic: "your-anthropic-key", // for Claude models
|
|
96
|
+
google: "your-google-key", // for Gemini models
|
|
97
|
+
openai: "your-openai-key", // for OpenAI models
|
|
98
|
+
},
|
|
103
99
|
});
|
|
104
100
|
```
|
|
105
101
|
|
|
106
|
-
| Option
|
|
107
|
-
|
|
108
|
-
| `model`
|
|
102
|
+
| Option | Type | Default | Description |
|
|
103
|
+
| ------------------- | -------- | --------------------------- | ------------------------------------------------------------ |
|
|
104
|
+
| `model` | `string` | `"claude-haiku-4-5"` | The LLM model to use for judging |
|
|
105
|
+
| `apiKeys` | `object` | - | API keys for providers (falls back to environment variables) |
|
|
106
|
+
| `apiKeys.anthropic` | `string` | `ANTHROPIC_API_KEY` env var | API key for Claude models |
|
|
107
|
+
| `apiKeys.google` | `string` | `GOOGLE_API_KEY` env var | API key for Gemini models |
|
|
108
|
+
| `apiKeys.openai` | `string` | `OPENAI_API_KEY` env var | API key for OpenAI models |
|
|
109
109
|
|
|
110
110
|
### `toSemanticallyMatch(expected, options?)`
|
|
111
111
|
|
|
@@ -119,16 +119,18 @@ await expect("Hello! How can I help you today?").toSemanticallyMatch(
|
|
|
119
119
|
|
|
120
120
|
**Options:**
|
|
121
121
|
|
|
122
|
-
| Option
|
|
123
|
-
|
|
122
|
+
| Option | Type | Default | Description |
|
|
123
|
+
| ----------- | ----------------------- | --------- | ------------------------------------------ |
|
|
124
124
|
| `threshold` | `"strict"` \| `"loose"` | `"loose"` | How strictly to judge semantic equivalence |
|
|
125
|
-
| `context`
|
|
125
|
+
| `context` | `string` | - | Additional context to help the LLM judge |
|
|
126
126
|
|
|
127
127
|
**Examples:**
|
|
128
128
|
|
|
129
129
|
```typescript
|
|
130
130
|
// Basic usage
|
|
131
|
-
await expect("The sky is blue").toSemanticallyMatch(
|
|
131
|
+
await expect("The sky is blue").toSemanticallyMatch(
|
|
132
|
+
"The color of the sky is blue"
|
|
133
|
+
);
|
|
132
134
|
|
|
133
135
|
// With strict threshold
|
|
134
136
|
await expect(response).toSemanticallyMatch("The capital of France is Paris", {
|
|
@@ -141,7 +143,9 @@ await expect("Paris").toSemanticallyMatch("The capital of France", {
|
|
|
141
143
|
});
|
|
142
144
|
|
|
143
145
|
// Negation
|
|
144
|
-
await expect("I love sunny weather").not.toSemanticallyMatch(
|
|
146
|
+
await expect("I love sunny weather").not.toSemanticallyMatch(
|
|
147
|
+
"I hate sunny weather"
|
|
148
|
+
);
|
|
145
149
|
```
|
|
146
150
|
|
|
147
151
|
### `toSatisfy(criteria)`
|
|
@@ -167,28 +171,44 @@ await expect(response).toSatisfy("is polite and professional in tone");
|
|
|
167
171
|
await expect(output).toSatisfy("is valid JSON containing a 'name' field");
|
|
168
172
|
|
|
169
173
|
// Testing safety
|
|
170
|
-
await expect(response).not.toSatisfy(
|
|
174
|
+
await expect(response).not.toSatisfy(
|
|
175
|
+
"contains profanity or offensive language"
|
|
176
|
+
);
|
|
171
177
|
```
|
|
172
178
|
|
|
173
179
|
## Configuration
|
|
174
180
|
|
|
175
|
-
###
|
|
181
|
+
### API Keys
|
|
176
182
|
|
|
177
|
-
|
|
183
|
+
You can provide API keys in two ways:
|
|
178
184
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
185
|
+
**1. Direct configuration (recommended):**
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
configure({
|
|
189
|
+
apiKeys: {
|
|
190
|
+
anthropic: process.env.MY_ANTHROPIC_KEY, // or hardcoded string
|
|
191
|
+
},
|
|
192
|
+
});
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**2. Environment variables (fallback):**
|
|
196
|
+
|
|
197
|
+
| Model | Environment Variable |
|
|
198
|
+
| ------------------------ | -------------------- |
|
|
199
|
+
| `claude-haiku-4-5` | `ANTHROPIC_API_KEY` |
|
|
200
|
+
| `gemini-3-flash-preview` | `GOOGLE_API_KEY` |
|
|
201
|
+
| `gpt-5-nano` | `OPENAI_API_KEY` |
|
|
202
|
+
|
|
203
|
+
Direct configuration takes precedence over environment variables.
|
|
184
204
|
|
|
185
205
|
### Supported Models
|
|
186
206
|
|
|
187
|
-
| Model ID
|
|
188
|
-
|
|
189
|
-
| `claude-haiku-4-5`
|
|
190
|
-
| `gemini-3-flash-preview` | Google
|
|
191
|
-
| `gpt-5-nano`
|
|
207
|
+
| Model ID | Provider | Description |
|
|
208
|
+
| ------------------------ | --------- | ------------------------------------------- |
|
|
209
|
+
| `claude-haiku-4-5` | Anthropic | Fast, cost-effective Claude model (default) |
|
|
210
|
+
| `gemini-3-flash-preview` | Google | Fast Gemini model |
|
|
211
|
+
| `gpt-5-nano` | OpenAI | Lightweight GPT model |
|
|
192
212
|
|
|
193
213
|
## TypeScript Support
|
|
194
214
|
|
|
@@ -216,6 +236,7 @@ pleasant weather conditions, while the second describes heavy rainfall.
|
|
|
216
236
|
## Best Practices
|
|
217
237
|
|
|
218
238
|
1. **Use semantic matching for equivalent meanings**, not for checking specific content:
|
|
239
|
+
|
|
219
240
|
```typescript
|
|
220
241
|
// Good: checking semantic equivalence
|
|
221
242
|
await expect(greeting).toSemanticallyMatch("Hello, how can I help?");
|
|
@@ -225,6 +246,7 @@ pleasant weather conditions, while the second describes heavy rainfall.
|
|
|
225
246
|
```
|
|
226
247
|
|
|
227
248
|
2. **Provide context when the comparison needs domain knowledge:**
|
|
249
|
+
|
|
228
250
|
```typescript
|
|
229
251
|
await expect("42").toSemanticallyMatch("The answer", {
|
|
230
252
|
context: "Testing a Hitchhiker's Guide to the Galaxy trivia bot",
|
|
@@ -232,6 +254,7 @@ pleasant weather conditions, while the second describes heavy rainfall.
|
|
|
232
254
|
```
|
|
233
255
|
|
|
234
256
|
3. **Use `threshold: "strict"` when precision matters:**
|
|
257
|
+
|
|
235
258
|
```typescript
|
|
236
259
|
await expect(legalText).toSemanticallyMatch(expectedDisclaimer, {
|
|
237
260
|
threshold: "strict",
|
package/dist/cjs/config.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import type { JestFuzzyConfig, LLMProvider } from "./types.js";
|
|
1
|
+
import type { JestFuzzyConfig, ModelName, ApiKeys, LLMProvider } from "./types.js";
|
|
2
2
|
export declare function configure(config?: JestFuzzyConfig): void;
|
|
3
|
-
export declare function getConfig():
|
|
3
|
+
export declare function getConfig(): {
|
|
4
|
+
model: ModelName;
|
|
5
|
+
apiKeys?: ApiKeys;
|
|
6
|
+
};
|
|
4
7
|
export declare function getProvider(): Promise<LLMProvider>;
|
|
5
8
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/cjs/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAYnF,wBAAgB,SAAS,CAAC,MAAM,GAAE,eAAoB,GAAG,IAAI,CAS5D;AAED,wBAAgB,SAAS,IAAI;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAKnE;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC,CAcxD"}
|
package/dist/cjs/config.js
CHANGED
|
@@ -13,6 +13,7 @@ let providerPromise = null;
|
|
|
13
13
|
function configure(config = {}) {
|
|
14
14
|
currentConfig = {
|
|
15
15
|
model: config.model ?? DEFAULT_MODEL,
|
|
16
|
+
apiKeys: config.apiKeys,
|
|
16
17
|
};
|
|
17
18
|
// Reset provider so it will be re-created with new config
|
|
18
19
|
providerInstance = null;
|
|
@@ -21,6 +22,7 @@ function configure(config = {}) {
|
|
|
21
22
|
function getConfig() {
|
|
22
23
|
return {
|
|
23
24
|
model: currentConfig.model ?? DEFAULT_MODEL,
|
|
25
|
+
apiKeys: currentConfig.apiKeys,
|
|
24
26
|
};
|
|
25
27
|
}
|
|
26
28
|
async function getProvider() {
|
|
@@ -28,7 +30,8 @@ async function getProvider() {
|
|
|
28
30
|
return providerInstance;
|
|
29
31
|
}
|
|
30
32
|
if (!providerPromise) {
|
|
31
|
-
|
|
33
|
+
const config = getConfig();
|
|
34
|
+
providerPromise = (0, index_js_1.createProvider)(config.model, config.apiKeys).then((provider) => {
|
|
32
35
|
providerInstance = provider;
|
|
33
36
|
return provider;
|
|
34
37
|
});
|
package/dist/cjs/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":";;AAYA,
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":";;AAYA,8BASC;AAED,8BAKC;AAED,kCAcC;AA3CD,mDAAsD;AAEtD,MAAM,aAAa,GAAc,kBAAkB,CAAC;AAEpD,IAAI,aAAa,GAAoB;IACnC,KAAK,EAAE,aAAa;CACrB,CAAC;AAEF,IAAI,gBAAgB,GAAuB,IAAI,CAAC;AAChD,IAAI,eAAe,GAAgC,IAAI,CAAC;AAExD,SAAgB,SAAS,CAAC,SAA0B,EAAE;IACpD,aAAa,GAAG;QACd,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,aAAa;QACpC,OAAO,EAAE,MAAM,CAAC,OAAO;KACxB,CAAC;IAEF,0DAA0D;IAC1D,gBAAgB,GAAG,IAAI,CAAC;IACxB,eAAe,GAAG,IAAI,CAAC;AACzB,CAAC;AAED,SAAgB,SAAS;IACvB,OAAO;QACL,KAAK,EAAE,aAAa,CAAC,KAAK,IAAI,aAAa;QAC3C,OAAO,EAAE,aAAa,CAAC,OAAO;KAC/B,CAAC;AACJ,CAAC;AAEM,KAAK,UAAU,WAAW;IAC/B,IAAI,gBAAgB,EAAE,CAAC;QACrB,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IAED,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,eAAe,GAAG,IAAA,yBAAc,EAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE;YAC/E,gBAAgB,GAAG,QAAQ,CAAC;YAC5B,OAAO,QAAQ,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,eAAe,CAAC;AACzB,CAAC"}
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { configure, getConfig, getProvider } from "./config.js";
|
|
2
|
-
import type { JestFuzzyConfig, SemanticMatchOptions, ModelName, LLMProvider } from "./types.js";
|
|
2
|
+
import type { JestFuzzyConfig, SemanticMatchOptions, ModelName, ApiKeys, LLMProvider } from "./types.js";
|
|
3
3
|
export { configure, getConfig, getProvider };
|
|
4
|
-
export type { JestFuzzyConfig, SemanticMatchOptions, ModelName, LLMProvider, };
|
|
4
|
+
export type { JestFuzzyConfig, SemanticMatchOptions, ModelName, ApiKeys, LLMProvider, };
|
|
5
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/cjs/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAGhE,OAAO,KAAK,EACV,eAAe,EACf,oBAAoB,EACpB,SAAS,EACT,WAAW,EACZ,MAAM,YAAY,CAAC;AAUpB,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;AAC7C,YAAY,EACV,eAAe,EACf,oBAAoB,EACpB,SAAS,EACT,WAAW,GACZ,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAGhE,OAAO,KAAK,EACV,eAAe,EACf,oBAAoB,EACpB,SAAS,EACT,OAAO,EACP,WAAW,EACZ,MAAM,YAAY,CAAC;AAUpB,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;AAC7C,YAAY,EACV,eAAe,EACf,oBAAoB,EACpB,SAAS,EACT,OAAO,EACP,WAAW,GACZ,CAAC"}
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,2CAAgE;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,2CAAgE;AAmBvD,0FAnBA,qBAAS,OAmBA;AAAE,0FAnBA,qBAAS,OAmBA;AAAE,4FAnBA,uBAAW,OAmBA;AAlB1C,8EAAwE;AACxE,0DAAoD;AASpD,8BAA8B;AAC9B,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;IACnD,MAAM,CAAC,MAAM,CAAC;QACZ,mBAAmB,EAAnB,4CAAmB;QACnB,SAAS,EAAT,wBAAS;KACV,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { LLMProvider, JudgmentResult } from "../types.js";
|
|
2
2
|
export declare class AnthropicProvider implements LLMProvider {
|
|
3
|
-
private
|
|
3
|
+
private apiKey;
|
|
4
4
|
private constructor();
|
|
5
|
-
static create(): Promise<AnthropicProvider>;
|
|
5
|
+
static create(apiKey?: string): Promise<AnthropicProvider>;
|
|
6
6
|
judge(prompt: string): Promise<JudgmentResult>;
|
|
7
7
|
}
|
|
8
8
|
//# sourceMappingURL=anthropic.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../../src/providers/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../../src/providers/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAoB/D,qBAAa,iBAAkB,YAAW,WAAW;IACnD,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO;WAIM,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAW1D,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;CAmCrD"}
|
|
@@ -1,93 +1,65 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
3
|
exports.AnthropicProvider = void 0;
|
|
4
|
+
const ANTHROPIC_API_URL = "https://api.anthropic.com/v1/messages";
|
|
37
5
|
const JUDGMENT_SCHEMA = {
|
|
38
|
-
type: "
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
type: "string",
|
|
48
|
-
description: "Brief explanation of the reasoning",
|
|
49
|
-
},
|
|
6
|
+
type: "object",
|
|
7
|
+
properties: {
|
|
8
|
+
verdict: {
|
|
9
|
+
type: "boolean",
|
|
10
|
+
description: "true if the condition is satisfied, false otherwise",
|
|
11
|
+
},
|
|
12
|
+
explanation: {
|
|
13
|
+
type: "string",
|
|
14
|
+
description: "Brief explanation of the reasoning",
|
|
50
15
|
},
|
|
51
|
-
required: ["verdict", "explanation"],
|
|
52
|
-
additionalProperties: false,
|
|
53
16
|
},
|
|
17
|
+
required: ["verdict", "explanation"],
|
|
18
|
+
additionalProperties: false,
|
|
54
19
|
};
|
|
55
20
|
class AnthropicProvider {
|
|
56
|
-
|
|
57
|
-
constructor(
|
|
58
|
-
this.
|
|
21
|
+
apiKey;
|
|
22
|
+
constructor(apiKey) {
|
|
23
|
+
this.apiKey = apiKey;
|
|
59
24
|
}
|
|
60
|
-
static async create() {
|
|
61
|
-
const
|
|
62
|
-
if (!
|
|
63
|
-
throw new Error("jest-fuzzy: Missing
|
|
64
|
-
|
|
65
|
-
try {
|
|
66
|
-
const module = await Promise.resolve().then(() => __importStar(require("@anthropic-ai/sdk")));
|
|
67
|
-
const Anthropic = module.default;
|
|
68
|
-
const client = new Anthropic({ apiKey });
|
|
69
|
-
return new AnthropicProvider(client);
|
|
70
|
-
}
|
|
71
|
-
catch (e) {
|
|
72
|
-
throw new Error("jest-fuzzy: To use claude-haiku-4-5, install @anthropic-ai/sdk");
|
|
25
|
+
static async create(apiKey) {
|
|
26
|
+
const key = apiKey ?? process.env.ANTHROPIC_API_KEY;
|
|
27
|
+
if (!key) {
|
|
28
|
+
throw new Error("jest-fuzzy: Missing API key for claude-haiku-4-5 model. " +
|
|
29
|
+
"Either pass it via configure({ apiKeys: { anthropic: '...' } }) or set ANTHROPIC_API_KEY environment variable.");
|
|
73
30
|
}
|
|
31
|
+
return new AnthropicProvider(key);
|
|
74
32
|
}
|
|
75
33
|
async judge(prompt) {
|
|
76
|
-
|
|
77
|
-
|
|
34
|
+
const response = await fetch(ANTHROPIC_API_URL, {
|
|
35
|
+
method: "POST",
|
|
36
|
+
headers: {
|
|
37
|
+
"content-type": "application/json",
|
|
38
|
+
"x-api-key": this.apiKey,
|
|
39
|
+
"anthropic-version": "2023-06-01",
|
|
40
|
+
"anthropic-beta": "structured-outputs-2025-11-13",
|
|
41
|
+
},
|
|
42
|
+
body: JSON.stringify({
|
|
78
43
|
model: "claude-haiku-4-5",
|
|
79
44
|
max_tokens: 1024,
|
|
80
|
-
betas: ["structured-outputs-2025-11-13"],
|
|
81
45
|
messages: [{ role: "user", content: prompt }],
|
|
82
|
-
output_format:
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
46
|
+
output_format: {
|
|
47
|
+
type: "json_schema",
|
|
48
|
+
schema: JUDGMENT_SCHEMA,
|
|
49
|
+
},
|
|
50
|
+
}),
|
|
51
|
+
});
|
|
52
|
+
if (!response.ok) {
|
|
53
|
+
const errorText = await response.text();
|
|
54
|
+
throw new Error(`jest-fuzzy: Anthropic API error (${response.status}): ${errorText}`);
|
|
87
55
|
}
|
|
88
|
-
|
|
89
|
-
|
|
56
|
+
const data = (await response.json());
|
|
57
|
+
const text = data.content?.[0]?.text;
|
|
58
|
+
if (!text) {
|
|
59
|
+
throw new Error("jest-fuzzy: Anthropic API returned no content");
|
|
90
60
|
}
|
|
61
|
+
const parsed = JSON.parse(text);
|
|
62
|
+
return { verdict: parsed.verdict, explanation: parsed.explanation };
|
|
91
63
|
}
|
|
92
64
|
}
|
|
93
65
|
exports.AnthropicProvider = AnthropicProvider;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/providers/anthropic.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/providers/anthropic.ts"],"names":[],"mappings":";;;AAEA,MAAM,iBAAiB,GAAG,uCAAuC,CAAC;AAElE,MAAM,eAAe,GAAG;IACtB,IAAI,EAAE,QAAiB;IACvB,UAAU,EAAE;QACV,OAAO,EAAE;YACP,IAAI,EAAE,SAAkB;YACxB,WAAW,EAAE,qDAAqD;SACnE;QACD,WAAW,EAAE;YACX,IAAI,EAAE,QAAiB;YACvB,WAAW,EAAE,oCAAoC;SAClD;KACF;IACD,QAAQ,EAAE,CAAC,SAAS,EAAE,aAAa,CAAC;IACpC,oBAAoB,EAAE,KAAK;CAC5B,CAAC;AAEF,MAAa,iBAAiB;IACpB,MAAM,CAAS;IAEvB,YAAoB,MAAc;QAChC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAe;QACjC,MAAM,GAAG,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;QACpD,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CACb,0DAA0D;gBACxD,gHAAgH,CACnH,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,iBAAiB,CAAC,GAAG,CAAC,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,MAAc;QACxB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,iBAAiB,EAAE;YAC9C,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,WAAW,EAAE,IAAI,CAAC,MAAM;gBACxB,mBAAmB,EAAE,YAAY;gBACjC,gBAAgB,EAAE,+BAA+B;aAClD;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK,EAAE,kBAAkB;gBACzB,UAAU,EAAE,IAAI;gBAChB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;gBAC7C,aAAa,EAAE;oBACb,IAAI,EAAE,aAAa;oBACnB,MAAM,EAAE,eAAe;iBACxB;aACF,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACxC,MAAM,IAAI,KAAK,CAAC,oCAAoC,QAAQ,CAAC,MAAM,MAAM,SAAS,EAAE,CAAC,CAAC;QACxF,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA2C,CAAC;QAC/E,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;QAErC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;QACnE,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAA8C,CAAC;QAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC;IACtE,CAAC;CACF;AArDD,8CAqDC"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { LLMProvider, JudgmentResult } from "../types.js";
|
|
2
2
|
export declare class GoogleProvider implements LLMProvider {
|
|
3
|
-
private
|
|
3
|
+
private apiKey;
|
|
4
4
|
private constructor();
|
|
5
|
-
static create(): Promise<GoogleProvider>;
|
|
5
|
+
static create(apiKey?: string): Promise<GoogleProvider>;
|
|
6
6
|
judge(prompt: string): Promise<JudgmentResult>;
|
|
7
7
|
}
|
|
8
8
|
//# sourceMappingURL=google.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"google.d.ts","sourceRoot":"","sources":["../../../src/providers/google.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"google.d.ts","sourceRoot":"","sources":["../../../src/providers/google.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAmB/D,qBAAa,cAAe,YAAW,WAAW;IAChD,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO;WAIM,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAWvD,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;CAsCrD"}
|
|
@@ -1,89 +1,64 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
3
|
exports.GoogleProvider = void 0;
|
|
4
|
+
const GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent";
|
|
5
|
+
const JUDGMENT_SCHEMA = {
|
|
6
|
+
type: "OBJECT",
|
|
7
|
+
properties: {
|
|
8
|
+
verdict: {
|
|
9
|
+
type: "BOOLEAN",
|
|
10
|
+
description: "true if the condition is satisfied, false otherwise",
|
|
11
|
+
},
|
|
12
|
+
explanation: {
|
|
13
|
+
type: "STRING",
|
|
14
|
+
description: "Brief explanation of the reasoning",
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
required: ["verdict", "explanation"],
|
|
18
|
+
};
|
|
37
19
|
class GoogleProvider {
|
|
38
|
-
|
|
39
|
-
constructor(
|
|
40
|
-
this.
|
|
20
|
+
apiKey;
|
|
21
|
+
constructor(apiKey) {
|
|
22
|
+
this.apiKey = apiKey;
|
|
41
23
|
}
|
|
42
|
-
static async create() {
|
|
43
|
-
const
|
|
44
|
-
if (!
|
|
45
|
-
throw new Error("jest-fuzzy: Missing
|
|
24
|
+
static async create(apiKey) {
|
|
25
|
+
const key = apiKey ?? process.env.GOOGLE_API_KEY;
|
|
26
|
+
if (!key) {
|
|
27
|
+
throw new Error("jest-fuzzy: Missing API key for gemini-3-flash-preview model. " +
|
|
28
|
+
"Either pass it via configure({ apiKeys: { google: '...' } }) or set GOOGLE_API_KEY environment variable.");
|
|
46
29
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
30
|
+
return new GoogleProvider(key);
|
|
31
|
+
}
|
|
32
|
+
async judge(prompt) {
|
|
33
|
+
const url = `${GEMINI_API_URL}?key=${this.apiKey}`;
|
|
34
|
+
const response = await fetch(url, {
|
|
35
|
+
method: "POST",
|
|
36
|
+
headers: {
|
|
37
|
+
"Content-Type": "application/json",
|
|
38
|
+
},
|
|
39
|
+
body: JSON.stringify({
|
|
40
|
+
contents: [
|
|
41
|
+
{
|
|
42
|
+
parts: [{ text: prompt }],
|
|
43
|
+
},
|
|
44
|
+
],
|
|
53
45
|
generationConfig: {
|
|
54
46
|
responseMimeType: "application/json",
|
|
55
|
-
responseSchema:
|
|
56
|
-
type: SchemaType.OBJECT,
|
|
57
|
-
properties: {
|
|
58
|
-
verdict: {
|
|
59
|
-
type: SchemaType.BOOLEAN,
|
|
60
|
-
description: "true if the condition is satisfied, false otherwise",
|
|
61
|
-
},
|
|
62
|
-
explanation: {
|
|
63
|
-
type: SchemaType.STRING,
|
|
64
|
-
description: "Brief explanation of the reasoning",
|
|
65
|
-
},
|
|
66
|
-
},
|
|
67
|
-
required: ["verdict", "explanation"],
|
|
68
|
-
},
|
|
47
|
+
responseSchema: JUDGMENT_SCHEMA,
|
|
69
48
|
},
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
throw new Error(
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
async judge(prompt) {
|
|
78
|
-
try {
|
|
79
|
-
const result = await this.model.generateContent(prompt);
|
|
80
|
-
const text = result.response.text();
|
|
81
|
-
const parsed = JSON.parse(text);
|
|
82
|
-
return { verdict: parsed.verdict, explanation: parsed.explanation };
|
|
49
|
+
}),
|
|
50
|
+
});
|
|
51
|
+
if (!response.ok) {
|
|
52
|
+
const errorText = await response.text();
|
|
53
|
+
throw new Error(`jest-fuzzy: Google API error (${response.status}): ${errorText}`);
|
|
83
54
|
}
|
|
84
|
-
|
|
85
|
-
|
|
55
|
+
const data = (await response.json());
|
|
56
|
+
const text = data.candidates?.[0]?.content?.parts?.[0]?.text;
|
|
57
|
+
if (!text) {
|
|
58
|
+
throw new Error("jest-fuzzy: Google API returned no content");
|
|
86
59
|
}
|
|
60
|
+
const parsed = JSON.parse(text);
|
|
61
|
+
return { verdict: parsed.verdict, explanation: parsed.explanation };
|
|
87
62
|
}
|
|
88
63
|
}
|
|
89
64
|
exports.GoogleProvider = GoogleProvider;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"google.js","sourceRoot":"","sources":["../../../src/providers/google.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"google.js","sourceRoot":"","sources":["../../../src/providers/google.ts"],"names":[],"mappings":";;;AAEA,MAAM,cAAc,GAAG,0FAA0F,CAAC;AAElH,MAAM,eAAe,GAAG;IACtB,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,OAAO,EAAE;YACP,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,qDAAqD;SACnE;QACD,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,oCAAoC;SAClD;KACF;IACD,QAAQ,EAAE,CAAC,SAAS,EAAE,aAAa,CAAC;CACrC,CAAC;AAEF,MAAa,cAAc;IACjB,MAAM,CAAS;IAEvB,YAAoB,MAAc;QAChC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAe;QACjC,MAAM,GAAG,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;QACjD,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CACb,gEAAgE;gBAC9D,0GAA0G,CAC7G,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,cAAc,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,MAAc;QACxB,MAAM,GAAG,GAAG,GAAG,cAAc,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;QAEnD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,QAAQ,EAAE;oBACR;wBACE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;qBAC1B;iBACF;gBACD,gBAAgB,EAAE;oBAChB,gBAAgB,EAAE,kBAAkB;oBACpC,cAAc,EAAE,eAAe;iBAChC;aACF,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACxC,MAAM,IAAI,KAAK,CAAC,iCAAiC,QAAQ,CAAC,MAAM,MAAM,SAAS,EAAE,CAAC,CAAC;QACrF,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAElC,CAAC;QACF,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;QAE7D,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAChE,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAA8C,CAAC;QAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC;IACtE,CAAC;CACF;AAxDD,wCAwDC"}
|