@jamesaphoenix/tx-test-utils 0.4.2
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/dist/database/index.d.ts +8 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/index.js +7 -0
- package/dist/database/index.js.map +1 -0
- package/dist/database/test-database.d.ts +101 -0
- package/dist/database/test-database.d.ts.map +1 -0
- package/dist/database/test-database.js +130 -0
- package/dist/database/test-database.js.map +1 -0
- package/dist/factories/anchor.factory.d.ts +117 -0
- package/dist/factories/anchor.factory.d.ts.map +1 -0
- package/dist/factories/anchor.factory.js +201 -0
- package/dist/factories/anchor.factory.js.map +1 -0
- package/dist/factories/candidate.factory.d.ts +151 -0
- package/dist/factories/candidate.factory.d.ts.map +1 -0
- package/dist/factories/candidate.factory.js +194 -0
- package/dist/factories/candidate.factory.js.map +1 -0
- package/dist/factories/edge.factory.d.ts +119 -0
- package/dist/factories/edge.factory.d.ts.map +1 -0
- package/dist/factories/edge.factory.js +191 -0
- package/dist/factories/edge.factory.js.map +1 -0
- package/dist/factories/factories.test.d.ts +8 -0
- package/dist/factories/factories.test.d.ts.map +1 -0
- package/dist/factories/factories.test.js +419 -0
- package/dist/factories/factories.test.js.map +1 -0
- package/dist/factories/index.d.ts +15 -0
- package/dist/factories/index.d.ts.map +1 -0
- package/dist/factories/index.js +21 -0
- package/dist/factories/index.js.map +1 -0
- package/dist/factories/learning.factory.d.ts +107 -0
- package/dist/factories/learning.factory.d.ts.map +1 -0
- package/dist/factories/learning.factory.js +150 -0
- package/dist/factories/learning.factory.js.map +1 -0
- package/dist/factories/task.factory.d.ts +106 -0
- package/dist/factories/task.factory.d.ts.map +1 -0
- package/dist/factories/task.factory.js +151 -0
- package/dist/factories/task.factory.js.map +1 -0
- package/dist/fixtures/index.d.ts +36 -0
- package/dist/fixtures/index.d.ts.map +1 -0
- package/dist/fixtures/index.js +47 -0
- package/dist/fixtures/index.js.map +1 -0
- package/dist/helpers/effect.d.ts +186 -0
- package/dist/helpers/effect.d.ts.map +1 -0
- package/dist/helpers/effect.js +298 -0
- package/dist/helpers/effect.js.map +1 -0
- package/dist/helpers/effect.test.d.ts +7 -0
- package/dist/helpers/effect.test.d.ts.map +1 -0
- package/dist/helpers/effect.test.js +271 -0
- package/dist/helpers/effect.test.js.map +1 -0
- package/dist/helpers/index.d.ts +7 -0
- package/dist/helpers/index.d.ts.map +1 -0
- package/dist/helpers/index.js +11 -0
- package/dist/helpers/index.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +52 -0
- package/dist/index.js.map +1 -0
- package/dist/llm-cache/cache.d.ts +152 -0
- package/dist/llm-cache/cache.d.ts.map +1 -0
- package/dist/llm-cache/cache.js +199 -0
- package/dist/llm-cache/cache.js.map +1 -0
- package/dist/llm-cache/cache.test.d.ts +7 -0
- package/dist/llm-cache/cache.test.d.ts.map +1 -0
- package/dist/llm-cache/cache.test.js +310 -0
- package/dist/llm-cache/cache.test.js.map +1 -0
- package/dist/llm-cache/cli.d.ts +113 -0
- package/dist/llm-cache/cli.d.ts.map +1 -0
- package/dist/llm-cache/cli.js +248 -0
- package/dist/llm-cache/cli.js.map +1 -0
- package/dist/llm-cache/index.d.ts +31 -0
- package/dist/llm-cache/index.d.ts.map +1 -0
- package/dist/llm-cache/index.js +31 -0
- package/dist/llm-cache/index.js.map +1 -0
- package/dist/mocks/anthropic.mock.d.ts +173 -0
- package/dist/mocks/anthropic.mock.d.ts.map +1 -0
- package/dist/mocks/anthropic.mock.js +125 -0
- package/dist/mocks/anthropic.mock.js.map +1 -0
- package/dist/mocks/ast-grep.mock.d.ts +216 -0
- package/dist/mocks/ast-grep.mock.d.ts.map +1 -0
- package/dist/mocks/ast-grep.mock.js +164 -0
- package/dist/mocks/ast-grep.mock.js.map +1 -0
- package/dist/mocks/file-system.mock.d.ts +181 -0
- package/dist/mocks/file-system.mock.d.ts.map +1 -0
- package/dist/mocks/file-system.mock.js +280 -0
- package/dist/mocks/file-system.mock.js.map +1 -0
- package/dist/mocks/index.d.ts +10 -0
- package/dist/mocks/index.d.ts.map +1 -0
- package/dist/mocks/index.js +16 -0
- package/dist/mocks/index.js.map +1 -0
- package/dist/mocks/mocks.test.d.ts +10 -0
- package/dist/mocks/mocks.test.d.ts.map +1 -0
- package/dist/mocks/mocks.test.js +961 -0
- package/dist/mocks/mocks.test.js.map +1 -0
- package/dist/mocks/openai.mock.d.ts +205 -0
- package/dist/mocks/openai.mock.d.ts.map +1 -0
- package/dist/mocks/openai.mock.js +178 -0
- package/dist/mocks/openai.mock.js.map +1 -0
- package/dist/setup/index.d.ts +7 -0
- package/dist/setup/index.d.ts.map +1 -0
- package/dist/setup/index.js +9 -0
- package/dist/setup/index.js.map +1 -0
- package/package.json +80 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/llm-cache/cli.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,EAAkB,UAAU,EAAE,MAAM,YAAY,CAAA;AAMvD;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAA;IACb,0BAA0B;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,8CAA8C;IAC9C,UAAU,EAAE,IAAI,GAAG,IAAI,CAAA;IACvB,8CAA8C;IAC9C,UAAU,EAAE,IAAI,GAAG,IAAI,CAAA;IACvB,gCAAgC;IAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,kCAAkC;IAClC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,0CAA0C;IAC1C,SAAS,CAAC,EAAE,IAAI,CAAA;IAChB,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,yBAAyB;IACzB,GAAG,CAAC,EAAE,OAAO,CAAA;CACd;AAMD;;;;;;;;;GASG;AACH,eAAO,MAAM,aAAa,QAAa,OAAO,CAAC,UAAU,CAqDxD,CAAA;AAMD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,UAAU,GAAU,UAAS,iBAAsB,KAAG,OAAO,CAAC,MAAM,CA+ChF,CAAA;AA2BD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,gBAAgB,GAAI,OAAO,UAAU,KAAG,MA4BpD,CAAA;AAMD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,GAAU,CAAC,GAAG,OAAO,EAAE,MAAM,MAAM,KAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAU3F,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,QAAa,OAAO,CAAC,MAAM,EAAE,CAWzD,CAAA"}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI utilities for LLM cache management.
|
|
3
|
+
*
|
|
4
|
+
* Provides functions to inspect, clear, and manage the LLM response cache.
|
|
5
|
+
*
|
|
6
|
+
* @module @tx/test-utils/llm-cache/cli
|
|
7
|
+
*/
|
|
8
|
+
import * as fs from "fs/promises";
|
|
9
|
+
import * as path from "path";
|
|
10
|
+
import { getCacheConfig } from "./cache.js";
|
|
11
|
+
// =============================================================================
|
|
12
|
+
// Cache Statistics
|
|
13
|
+
// =============================================================================
|
|
14
|
+
/**
|
|
15
|
+
* Get statistics about the LLM cache.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const stats = await getCacheStats()
|
|
20
|
+
* console.log(`Cache has ${stats.count} entries using ${stats.totalBytes} bytes`)
|
|
21
|
+
* console.log(`Models: ${Object.keys(stats.byModel).join(', ')}`)
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export const getCacheStats = async () => {
|
|
25
|
+
const config = getCacheConfig();
|
|
26
|
+
const stats = {
|
|
27
|
+
count: 0,
|
|
28
|
+
totalBytes: 0,
|
|
29
|
+
oldestDate: null,
|
|
30
|
+
newestDate: null,
|
|
31
|
+
byModel: {},
|
|
32
|
+
byVersion: {}
|
|
33
|
+
};
|
|
34
|
+
let files;
|
|
35
|
+
try {
|
|
36
|
+
files = await fs.readdir(config.cacheDir);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Directory doesn't exist - return empty stats
|
|
40
|
+
return stats;
|
|
41
|
+
}
|
|
42
|
+
const jsonFiles = files.filter((f) => f.endsWith(".json"));
|
|
43
|
+
stats.count = jsonFiles.length;
|
|
44
|
+
for (const file of jsonFiles) {
|
|
45
|
+
const filePath = path.join(config.cacheDir, file);
|
|
46
|
+
try {
|
|
47
|
+
const stat = await fs.stat(filePath);
|
|
48
|
+
stats.totalBytes += stat.size;
|
|
49
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
50
|
+
const entry = JSON.parse(content);
|
|
51
|
+
// Track by model
|
|
52
|
+
stats.byModel[entry.model] = (stats.byModel[entry.model] ?? 0) + 1;
|
|
53
|
+
// Track by version
|
|
54
|
+
stats.byVersion[entry.version] = (stats.byVersion[entry.version] ?? 0) + 1;
|
|
55
|
+
// Track date range
|
|
56
|
+
const date = new Date(entry.cachedAt);
|
|
57
|
+
if (!stats.oldestDate || date < stats.oldestDate) {
|
|
58
|
+
stats.oldestDate = date;
|
|
59
|
+
}
|
|
60
|
+
if (!stats.newestDate || date > stats.newestDate) {
|
|
61
|
+
stats.newestDate = date;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
// Skip corrupted files
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return stats;
|
|
70
|
+
};
|
|
71
|
+
// =============================================================================
|
|
72
|
+
// Cache Clearing
|
|
73
|
+
// =============================================================================
|
|
74
|
+
/**
|
|
75
|
+
* Clear cache entries based on options.
|
|
76
|
+
*
|
|
77
|
+
* @returns Number of entries deleted (-1 if unknown when using `all`)
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```typescript
|
|
81
|
+
* // Clear all cache
|
|
82
|
+
* await clearCache({ all: true })
|
|
83
|
+
*
|
|
84
|
+
* // Clear entries older than 30 days
|
|
85
|
+
* const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)
|
|
86
|
+
* const deleted = await clearCache({ olderThan: thirtyDaysAgo })
|
|
87
|
+
*
|
|
88
|
+
* // Clear entries for specific model
|
|
89
|
+
* await clearCache({ model: 'claude-haiku' })
|
|
90
|
+
*
|
|
91
|
+
* // Clear entries with specific version (useful after schema changes)
|
|
92
|
+
* await clearCache({ version: 1 })
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
export const clearCache = async (options = {}) => {
|
|
96
|
+
const config = getCacheConfig();
|
|
97
|
+
// Clear all - fastest path
|
|
98
|
+
if (options.all) {
|
|
99
|
+
try {
|
|
100
|
+
await fs.rm(config.cacheDir, { recursive: true, force: true });
|
|
101
|
+
await fs.mkdir(config.cacheDir, { recursive: true });
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// Directory may not exist
|
|
105
|
+
}
|
|
106
|
+
return -1; // Unknown count
|
|
107
|
+
}
|
|
108
|
+
let files;
|
|
109
|
+
try {
|
|
110
|
+
files = await fs.readdir(config.cacheDir);
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return 0; // Directory doesn't exist
|
|
114
|
+
}
|
|
115
|
+
const jsonFiles = files.filter((f) => f.endsWith(".json"));
|
|
116
|
+
let deleted = 0;
|
|
117
|
+
for (const file of jsonFiles) {
|
|
118
|
+
const filePath = path.join(config.cacheDir, file);
|
|
119
|
+
try {
|
|
120
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
121
|
+
const entry = JSON.parse(content);
|
|
122
|
+
const shouldDelete = (options.olderThan && new Date(entry.cachedAt) < options.olderThan) ||
|
|
123
|
+
(options.model && entry.model === options.model) ||
|
|
124
|
+
(options.version !== undefined && entry.version === options.version);
|
|
125
|
+
if (shouldDelete) {
|
|
126
|
+
await fs.unlink(filePath);
|
|
127
|
+
deleted++;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// Skip files that can't be read
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return deleted;
|
|
136
|
+
};
|
|
137
|
+
// =============================================================================
|
|
138
|
+
// Formatting
|
|
139
|
+
// =============================================================================
|
|
140
|
+
/**
|
|
141
|
+
* Format bytes into human-readable string.
|
|
142
|
+
*/
|
|
143
|
+
const formatBytes = (bytes) => {
|
|
144
|
+
if (bytes === 0)
|
|
145
|
+
return "0 B";
|
|
146
|
+
const units = ["B", "KB", "MB", "GB"];
|
|
147
|
+
const k = 1024;
|
|
148
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
149
|
+
return `${(bytes / Math.pow(k, i)).toFixed(1)} ${units[i]}`;
|
|
150
|
+
};
|
|
151
|
+
/**
|
|
152
|
+
* Format date for display.
|
|
153
|
+
*/
|
|
154
|
+
const formatDate = (date) => {
|
|
155
|
+
if (!date)
|
|
156
|
+
return "N/A";
|
|
157
|
+
return date.toISOString().split("T")[0];
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* Format cache statistics for display.
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* ```typescript
|
|
164
|
+
* const stats = await getCacheStats()
|
|
165
|
+
* console.log(formatCacheStats(stats))
|
|
166
|
+
* // Output:
|
|
167
|
+
* // LLM Cache Statistics:
|
|
168
|
+
* // Entries: 142
|
|
169
|
+
* // Size: 3.2 MB
|
|
170
|
+
* // Date range: 2024-01-15 to 2024-02-01
|
|
171
|
+
* // By model:
|
|
172
|
+
* // claude-sonnet-4: 98
|
|
173
|
+
* // claude-haiku: 44
|
|
174
|
+
* ```
|
|
175
|
+
*/
|
|
176
|
+
export const formatCacheStats = (stats) => {
|
|
177
|
+
const lines = [
|
|
178
|
+
"LLM Cache Statistics:",
|
|
179
|
+
` Entries: ${stats.count}`,
|
|
180
|
+
` Size: ${formatBytes(stats.totalBytes)}`
|
|
181
|
+
];
|
|
182
|
+
if (stats.oldestDate && stats.newestDate) {
|
|
183
|
+
lines.push(` Date range: ${formatDate(stats.oldestDate)} to ${formatDate(stats.newestDate)}`);
|
|
184
|
+
}
|
|
185
|
+
const models = Object.entries(stats.byModel);
|
|
186
|
+
if (models.length > 0) {
|
|
187
|
+
lines.push(" By model:");
|
|
188
|
+
for (const [model, count] of models.sort((a, b) => b[1] - a[1])) {
|
|
189
|
+
lines.push(` ${model}: ${count}`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const versions = Object.entries(stats.byVersion);
|
|
193
|
+
if (versions.length > 1) {
|
|
194
|
+
lines.push(" By version:");
|
|
195
|
+
for (const [version, count] of versions.sort((a, b) => Number(b[0]) - Number(a[0]))) {
|
|
196
|
+
lines.push(` v${version}: ${count}`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return lines.join("\n");
|
|
200
|
+
};
|
|
201
|
+
// =============================================================================
|
|
202
|
+
// Cache Entry Inspection
|
|
203
|
+
// =============================================================================
|
|
204
|
+
/**
|
|
205
|
+
* Get a specific cache entry by hash.
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* ```typescript
|
|
209
|
+
* const entry = await getCacheEntry('a1b2c3d4...')
|
|
210
|
+
* if (entry) {
|
|
211
|
+
* console.log(`Cached at: ${entry.cachedAt}`)
|
|
212
|
+
* console.log(`Model: ${entry.model}`)
|
|
213
|
+
* }
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
216
|
+
export const getCacheEntry = async (hash) => {
|
|
217
|
+
const config = getCacheConfig();
|
|
218
|
+
const filePath = path.join(config.cacheDir, `${hash}.json`);
|
|
219
|
+
try {
|
|
220
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
221
|
+
return JSON.parse(content);
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
/**
|
|
228
|
+
* List all cache entry hashes.
|
|
229
|
+
*
|
|
230
|
+
* @example
|
|
231
|
+
* ```typescript
|
|
232
|
+
* const hashes = await listCacheEntries()
|
|
233
|
+
* console.log(`Found ${hashes.length} cached responses`)
|
|
234
|
+
* ```
|
|
235
|
+
*/
|
|
236
|
+
export const listCacheEntries = async () => {
|
|
237
|
+
const config = getCacheConfig();
|
|
238
|
+
try {
|
|
239
|
+
const files = await fs.readdir(config.cacheDir);
|
|
240
|
+
return files
|
|
241
|
+
.filter((f) => f.endsWith(".json"))
|
|
242
|
+
.map((f) => f.replace(".json", ""));
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
return [];
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/llm-cache/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM response caching for deterministic tests.
|
|
3
|
+
*
|
|
4
|
+
* Caches expensive LLM API calls by hashing inputs with SHA256.
|
|
5
|
+
* Enables fast, repeatable tests without hitting real APIs.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { cachedLLMCall, withLLMCache, hashInput } from '@tx/test-utils/llm-cache'
|
|
10
|
+
*
|
|
11
|
+
* // Direct caching
|
|
12
|
+
* const result = await cachedLLMCall(
|
|
13
|
+
* "What is 2+2?",
|
|
14
|
+
* "claude-sonnet-4",
|
|
15
|
+
* () => anthropic.messages.create({...})
|
|
16
|
+
* )
|
|
17
|
+
*
|
|
18
|
+
* // Wrapper pattern
|
|
19
|
+
* const cachedExtract = withLLMCache(extractCandidates, {
|
|
20
|
+
* model: "claude-sonnet-4",
|
|
21
|
+
* version: 1
|
|
22
|
+
* })
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @module @tx/test-utils/llm-cache
|
|
26
|
+
*/
|
|
27
|
+
export { hashInput, cachedLLMCall, withLLMCache, configureLLMCache, getCacheConfig, resetCacheConfig } from "./cache.js";
|
|
28
|
+
export type { CacheEntry, CachedLLMCallOptions, WithLLMCacheOptions } from "./cache.js";
|
|
29
|
+
export { getCacheStats, clearCache, formatCacheStats, getCacheEntry, listCacheEntries } from "./cli.js";
|
|
30
|
+
export type { CacheStats, ClearCacheOptions } from "./cli.js";
|
|
31
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/llm-cache/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAGH,OAAO,EACL,SAAS,EACT,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EACjB,MAAM,YAAY,CAAA;AAGnB,YAAY,EACV,UAAU,EACV,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,YAAY,CAAA;AAGnB,OAAO,EACL,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,aAAa,EACb,gBAAgB,EACjB,MAAM,UAAU,CAAA;AAGjB,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM response caching for deterministic tests.
|
|
3
|
+
*
|
|
4
|
+
* Caches expensive LLM API calls by hashing inputs with SHA256.
|
|
5
|
+
* Enables fast, repeatable tests without hitting real APIs.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { cachedLLMCall, withLLMCache, hashInput } from '@tx/test-utils/llm-cache'
|
|
10
|
+
*
|
|
11
|
+
* // Direct caching
|
|
12
|
+
* const result = await cachedLLMCall(
|
|
13
|
+
* "What is 2+2?",
|
|
14
|
+
* "claude-sonnet-4",
|
|
15
|
+
* () => anthropic.messages.create({...})
|
|
16
|
+
* )
|
|
17
|
+
*
|
|
18
|
+
* // Wrapper pattern
|
|
19
|
+
* const cachedExtract = withLLMCache(extractCandidates, {
|
|
20
|
+
* model: "claude-sonnet-4",
|
|
21
|
+
* version: 1
|
|
22
|
+
* })
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @module @tx/test-utils/llm-cache
|
|
26
|
+
*/
|
|
27
|
+
// Core caching functions
|
|
28
|
+
export { hashInput, cachedLLMCall, withLLMCache, configureLLMCache, getCacheConfig, resetCacheConfig } from "./cache.js";
|
|
29
|
+
// CLI utilities
|
|
30
|
+
export { getCacheStats, clearCache, formatCacheStats, getCacheEntry, listCacheEntries } from "./cli.js";
|
|
31
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/llm-cache/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,yBAAyB;AACzB,OAAO,EACL,SAAS,EACT,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EACjB,MAAM,YAAY,CAAA;AASnB,gBAAgB;AAChB,OAAO,EACL,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,aAAa,EACb,gBAAgB,EACjB,MAAM,UAAU,CAAA"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock Anthropic client for testing.
|
|
3
|
+
*
|
|
4
|
+
* Provides configurable mock Anthropic clients with call tracking,
|
|
5
|
+
* response fixtures, and failure injection for testing services
|
|
6
|
+
* that depend on the Anthropic API.
|
|
7
|
+
*
|
|
8
|
+
* @module @tx/test-utils/mocks/anthropic
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Message structure matching Anthropic SDK format.
|
|
12
|
+
*/
|
|
13
|
+
export interface MockMessage {
|
|
14
|
+
role: "user" | "assistant";
|
|
15
|
+
content: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Tracked API call parameters.
|
|
19
|
+
*/
|
|
20
|
+
export interface MockAnthropicCall {
|
|
21
|
+
model: string;
|
|
22
|
+
messages: Array<{
|
|
23
|
+
role: string;
|
|
24
|
+
content: string;
|
|
25
|
+
}>;
|
|
26
|
+
max_tokens?: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Response structure matching Anthropic SDK format.
|
|
30
|
+
*/
|
|
31
|
+
export interface MockAnthropicResponse {
|
|
32
|
+
id: string;
|
|
33
|
+
type: "message";
|
|
34
|
+
role: "assistant";
|
|
35
|
+
content: Array<{
|
|
36
|
+
type: string;
|
|
37
|
+
text?: string;
|
|
38
|
+
}>;
|
|
39
|
+
model: string;
|
|
40
|
+
usage?: {
|
|
41
|
+
input_tokens?: number;
|
|
42
|
+
output_tokens?: number;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Configuration options for the mock Anthropic client.
|
|
47
|
+
*/
|
|
48
|
+
export interface MockAnthropicConfig {
|
|
49
|
+
/**
|
|
50
|
+
* Map of specific responses keyed by JSON-serialized messages.
|
|
51
|
+
* Allows returning different responses for different inputs.
|
|
52
|
+
*/
|
|
53
|
+
responses?: Map<string, MockAnthropicResponse>;
|
|
54
|
+
/**
|
|
55
|
+
* Default response when no specific response matches.
|
|
56
|
+
* If not provided, returns an empty array response.
|
|
57
|
+
*/
|
|
58
|
+
defaultResponse?: MockAnthropicResponse;
|
|
59
|
+
/**
|
|
60
|
+
* When true, all API calls will throw an error.
|
|
61
|
+
*/
|
|
62
|
+
shouldFail?: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Custom error message when shouldFail is true.
|
|
65
|
+
* Defaults to "Mock Anthropic API error".
|
|
66
|
+
*/
|
|
67
|
+
failureMessage?: string;
|
|
68
|
+
/**
|
|
69
|
+
* Custom error to throw when shouldFail is true.
|
|
70
|
+
* Takes precedence over failureMessage.
|
|
71
|
+
*/
|
|
72
|
+
failureError?: Error;
|
|
73
|
+
/**
|
|
74
|
+
* Simulated latency in milliseconds.
|
|
75
|
+
* Useful for testing timeout handling.
|
|
76
|
+
*/
|
|
77
|
+
latencyMs?: number;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Result returned by createMockAnthropic.
|
|
81
|
+
*/
|
|
82
|
+
export interface MockAnthropicResult {
|
|
83
|
+
/**
|
|
84
|
+
* The mock client that can be used in place of the real Anthropic SDK.
|
|
85
|
+
*/
|
|
86
|
+
client: {
|
|
87
|
+
messages: {
|
|
88
|
+
create(params: MockAnthropicCall): Promise<MockAnthropicResponse>;
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Array of all calls made to the mock client.
|
|
93
|
+
* Useful for assertions about API usage.
|
|
94
|
+
*/
|
|
95
|
+
calls: MockAnthropicCall[];
|
|
96
|
+
/**
|
|
97
|
+
* Reset the calls array to empty.
|
|
98
|
+
*/
|
|
99
|
+
reset: () => void;
|
|
100
|
+
/**
|
|
101
|
+
* Get the total number of calls made.
|
|
102
|
+
*/
|
|
103
|
+
getCallCount: () => number;
|
|
104
|
+
/**
|
|
105
|
+
* Get the most recent call made, or undefined if no calls.
|
|
106
|
+
*/
|
|
107
|
+
getLastCall: () => MockAnthropicCall | undefined;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Create a mock Anthropic client for testing.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* // Basic usage
|
|
115
|
+
* const mock = createMockAnthropic()
|
|
116
|
+
* const response = await mock.client.messages.create({
|
|
117
|
+
* model: "claude-haiku-4-20250514",
|
|
118
|
+
* max_tokens: 256,
|
|
119
|
+
* messages: [{ role: "user", content: "Hello" }]
|
|
120
|
+
* })
|
|
121
|
+
* expect(mock.calls).toHaveLength(1)
|
|
122
|
+
* ```
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```typescript
|
|
126
|
+
* // With custom response
|
|
127
|
+
* const mock = createMockAnthropic({
|
|
128
|
+
* defaultResponse: {
|
|
129
|
+
* id: "test-id",
|
|
130
|
+
* type: "message",
|
|
131
|
+
* role: "assistant",
|
|
132
|
+
* content: [{ type: "text", text: "Custom response" }],
|
|
133
|
+
* model: "claude-haiku-4-20250514",
|
|
134
|
+
* usage: { input_tokens: 10, output_tokens: 5 }
|
|
135
|
+
* }
|
|
136
|
+
* })
|
|
137
|
+
* ```
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```typescript
|
|
141
|
+
* // With failure injection
|
|
142
|
+
* const mock = createMockAnthropic({
|
|
143
|
+
* shouldFail: true,
|
|
144
|
+
* failureMessage: "Rate limit exceeded"
|
|
145
|
+
* })
|
|
146
|
+
* await expect(mock.client.messages.create(params)).rejects.toThrow("Rate limit exceeded")
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
export declare const createMockAnthropic: (config?: MockAnthropicConfig) => MockAnthropicResult;
|
|
150
|
+
/**
|
|
151
|
+
* Create a mock Anthropic client configured to return specific extraction candidates.
|
|
152
|
+
*
|
|
153
|
+
* This is a convenience factory for testing CandidateExtractorService and similar
|
|
154
|
+
* services that expect JSON array responses from the LLM.
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* ```typescript
|
|
158
|
+
* const mock = createMockAnthropicForExtraction([
|
|
159
|
+
* { content: "Always use transactions", confidence: "high", category: "patterns" },
|
|
160
|
+
* { content: "Test database migrations", confidence: "medium", category: "testing" }
|
|
161
|
+
* ])
|
|
162
|
+
*
|
|
163
|
+
* // The mock will return these candidates as JSON text
|
|
164
|
+
* const response = await mock.client.messages.create({ ... })
|
|
165
|
+
* // response.content[0].text === '[{"content":"Always use transactions",...}]'
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
export declare const createMockAnthropicForExtraction: (candidates: Array<{
|
|
169
|
+
content: string;
|
|
170
|
+
confidence: string;
|
|
171
|
+
category: string;
|
|
172
|
+
}>) => MockAnthropicResult;
|
|
173
|
+
//# sourceMappingURL=anthropic.mock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.mock.d.ts","sourceRoot":"","sources":["../../src/mocks/anthropic.mock.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,GAAG,WAAW,CAAA;IAC1B,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAClD,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,SAAS,CAAA;IACf,IAAI,EAAE,WAAW,CAAA;IACjB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC/C,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAC1D;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAA;IAC9C;;;OAGG;IACH,eAAe,CAAC,EAAE,qBAAqB,CAAA;IACvC;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;OAGG;IACH,YAAY,CAAC,EAAE,KAAK,CAAA;IACpB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,MAAM,EAAE;QACN,QAAQ,EAAE;YACR,MAAM,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAA;SAClE,CAAA;KACF,CAAA;IACD;;;OAGG;IACH,KAAK,EAAE,iBAAiB,EAAE,CAAA;IAC1B;;OAEG;IACH,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB;;OAEG;IACH,YAAY,EAAE,MAAM,MAAM,CAAA;IAC1B;;OAEG;IACH,WAAW,EAAE,MAAM,iBAAiB,GAAG,SAAS,CAAA;CACjD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,eAAO,MAAM,mBAAmB,GAAI,SAAQ,mBAAwB,KAAG,mBAkDtE,CAAA;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,gCAAgC,GAC3C,YAAY,KAAK,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,KAC3E,mBAWF,CAAA"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock Anthropic client for testing.
|
|
3
|
+
*
|
|
4
|
+
* Provides configurable mock Anthropic clients with call tracking,
|
|
5
|
+
* response fixtures, and failure injection for testing services
|
|
6
|
+
* that depend on the Anthropic API.
|
|
7
|
+
*
|
|
8
|
+
* @module @tx/test-utils/mocks/anthropic
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Create a mock Anthropic client for testing.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* // Basic usage
|
|
16
|
+
* const mock = createMockAnthropic()
|
|
17
|
+
* const response = await mock.client.messages.create({
|
|
18
|
+
* model: "claude-haiku-4-20250514",
|
|
19
|
+
* max_tokens: 256,
|
|
20
|
+
* messages: [{ role: "user", content: "Hello" }]
|
|
21
|
+
* })
|
|
22
|
+
* expect(mock.calls).toHaveLength(1)
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* // With custom response
|
|
28
|
+
* const mock = createMockAnthropic({
|
|
29
|
+
* defaultResponse: {
|
|
30
|
+
* id: "test-id",
|
|
31
|
+
* type: "message",
|
|
32
|
+
* role: "assistant",
|
|
33
|
+
* content: [{ type: "text", text: "Custom response" }],
|
|
34
|
+
* model: "claude-haiku-4-20250514",
|
|
35
|
+
* usage: { input_tokens: 10, output_tokens: 5 }
|
|
36
|
+
* }
|
|
37
|
+
* })
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```typescript
|
|
42
|
+
* // With failure injection
|
|
43
|
+
* const mock = createMockAnthropic({
|
|
44
|
+
* shouldFail: true,
|
|
45
|
+
* failureMessage: "Rate limit exceeded"
|
|
46
|
+
* })
|
|
47
|
+
* await expect(mock.client.messages.create(params)).rejects.toThrow("Rate limit exceeded")
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export const createMockAnthropic = (config = {}) => {
|
|
51
|
+
const calls = [];
|
|
52
|
+
const client = {
|
|
53
|
+
messages: {
|
|
54
|
+
create: async (params) => {
|
|
55
|
+
// Track the call
|
|
56
|
+
calls.push(params);
|
|
57
|
+
// Simulate latency if configured
|
|
58
|
+
if (config.latencyMs) {
|
|
59
|
+
await new Promise(resolve => setTimeout(resolve, config.latencyMs));
|
|
60
|
+
}
|
|
61
|
+
// Handle failure injection
|
|
62
|
+
if (config.shouldFail) {
|
|
63
|
+
throw config.failureError || new Error(config.failureMessage || "Mock Anthropic API error");
|
|
64
|
+
}
|
|
65
|
+
// Check for specific response by message content
|
|
66
|
+
if (config.responses) {
|
|
67
|
+
const key = JSON.stringify(params.messages);
|
|
68
|
+
const specificResponse = config.responses.get(key);
|
|
69
|
+
if (specificResponse) {
|
|
70
|
+
return specificResponse;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Return default response or a minimal valid response
|
|
74
|
+
return config.defaultResponse || {
|
|
75
|
+
id: "mock-msg-id",
|
|
76
|
+
type: "message",
|
|
77
|
+
role: "assistant",
|
|
78
|
+
content: [{ type: "text", text: "[]" }],
|
|
79
|
+
model: params.model,
|
|
80
|
+
usage: { input_tokens: 10, output_tokens: 5 }
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
return {
|
|
86
|
+
client,
|
|
87
|
+
calls,
|
|
88
|
+
reset: () => {
|
|
89
|
+
calls.length = 0;
|
|
90
|
+
},
|
|
91
|
+
getCallCount: () => calls.length,
|
|
92
|
+
getLastCall: () => calls[calls.length - 1]
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Create a mock Anthropic client configured to return specific extraction candidates.
|
|
97
|
+
*
|
|
98
|
+
* This is a convenience factory for testing CandidateExtractorService and similar
|
|
99
|
+
* services that expect JSON array responses from the LLM.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```typescript
|
|
103
|
+
* const mock = createMockAnthropicForExtraction([
|
|
104
|
+
* { content: "Always use transactions", confidence: "high", category: "patterns" },
|
|
105
|
+
* { content: "Test database migrations", confidence: "medium", category: "testing" }
|
|
106
|
+
* ])
|
|
107
|
+
*
|
|
108
|
+
* // The mock will return these candidates as JSON text
|
|
109
|
+
* const response = await mock.client.messages.create({ ... })
|
|
110
|
+
* // response.content[0].text === '[{"content":"Always use transactions",...}]'
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
export const createMockAnthropicForExtraction = (candidates) => {
|
|
114
|
+
return createMockAnthropic({
|
|
115
|
+
defaultResponse: {
|
|
116
|
+
id: "mock-extraction-id",
|
|
117
|
+
type: "message",
|
|
118
|
+
role: "assistant",
|
|
119
|
+
content: [{ type: "text", text: JSON.stringify(candidates) }],
|
|
120
|
+
model: "claude-haiku-4-20250514",
|
|
121
|
+
usage: { input_tokens: 100, output_tokens: 50 }
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
};
|
|
125
|
+
//# sourceMappingURL=anthropic.mock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.mock.js","sourceRoot":"","sources":["../../src/mocks/anthropic.mock.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAiGH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,SAA8B,EAAE,EAAuB,EAAE;IAC3F,MAAM,KAAK,GAAwB,EAAE,CAAA;IAErC,MAAM,MAAM,GAAG;QACb,QAAQ,EAAE;YACR,MAAM,EAAE,KAAK,EAAE,MAAyB,EAAkC,EAAE;gBAC1E,iBAAiB;gBACjB,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;gBAElB,iCAAiC;gBACjC,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;oBACrB,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,CAAA;gBACrE,CAAC;gBAED,2BAA2B;gBAC3B,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;oBACtB,MAAM,MAAM,CAAC,YAAY,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC,cAAc,IAAI,0BAA0B,CAAC,CAAA;gBAC7F,CAAC;gBAED,iDAAiD;gBACjD,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;oBACrB,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;oBAC3C,MAAM,gBAAgB,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;oBAClD,IAAI,gBAAgB,EAAE,CAAC;wBACrB,OAAO,gBAAgB,CAAA;oBACzB,CAAC;gBACH,CAAC;gBAED,sDAAsD;gBACtD,OAAO,MAAM,CAAC,eAAe,IAAI;oBAC/B,EAAE,EAAE,aAAa;oBACjB,IAAI,EAAE,SAAS;oBACf,IAAI,EAAE,WAAW;oBACjB,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;oBACvC,KAAK,EAAE,MAAM,CAAC,KAAK;oBACnB,KAAK,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,aAAa,EAAE,CAAC,EAAE;iBAC9C,CAAA;YACH,CAAC;SACF;KACF,CAAA;IAED,OAAO;QACL,MAAM;QACN,KAAK;QACL,KAAK,EAAE,GAAG,EAAE;YACV,KAAK,CAAC,MAAM,GAAG,CAAC,CAAA;QAClB,CAAC;QACD,YAAY,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM;QAChC,WAAW,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;KAC3C,CAAA;AACH,CAAC,CAAA;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,CAC9C,UAA4E,EACvD,EAAE;IACvB,OAAO,mBAAmB,CAAC;QACzB,eAAe,EAAE;YACf,EAAE,EAAE,oBAAoB;YACxB,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,WAAW;YACjB,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;YAC7D,KAAK,EAAE,yBAAyB;YAChC,KAAK,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,EAAE,EAAE,EAAE;SAChD;KACF,CAAC,CAAA;AACJ,CAAC,CAAA"}
|