@sochdb/sochdb 0.4.0 → 0.4.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 +220 -33
- package/_bin/aarch64-apple-darwin/libsochdb_storage.dylib +0 -0
- package/_bin/aarch64-apple-darwin/sochdb-bulk +0 -0
- package/_bin/aarch64-apple-darwin/sochdb-grpc-server +0 -0
- package/_bin/aarch64-apple-darwin/sochdb-server +0 -0
- package/_bin/x86_64-pc-windows-msvc/sochdb-bulk.exe +0 -0
- package/_bin/x86_64-pc-windows-msvc/sochdb-grpc-server.exe +0 -0
- package/_bin/x86_64-pc-windows-msvc/sochdb_storage.dll +0 -0
- package/_bin/x86_64-unknown-linux-gnu/libsochdb_storage.so +0 -0
- package/_bin/x86_64-unknown-linux-gnu/sochdb-bulk +0 -0
- package/_bin/x86_64-unknown-linux-gnu/sochdb-grpc-server +0 -0
- package/_bin/x86_64-unknown-linux-gnu/sochdb-server +0 -0
- package/bin/sochdb-bulk.js +1 -1
- package/bin/sochdb-grpc-server.js +1 -1
- package/bin/sochdb-server.js +1 -1
- package/dist/cjs/context-builder.js +280 -0
- package/dist/cjs/database.js +2 -2
- package/dist/cjs/embedded/database.js +2 -2
- package/dist/cjs/errors.js +99 -7
- package/dist/cjs/index.js +40 -3
- package/dist/cjs/ipc-client.js +2 -2
- package/dist/cjs/memory/consolidation.js +202 -0
- package/dist/cjs/memory/extraction.js +181 -0
- package/dist/cjs/memory/index.js +26 -0
- package/dist/cjs/memory/retrieval.js +232 -0
- package/dist/cjs/memory/types.js +69 -0
- package/dist/cjs/namespace.js +255 -0
- package/dist/cjs/queue.js +289 -0
- package/dist/cjs/semantic-cache.js +220 -0
- package/dist/esm/context-builder.js +280 -0
- package/dist/esm/database.js +2 -2
- package/dist/esm/embedded/database.js +2 -2
- package/dist/esm/errors.js +107 -7
- package/dist/esm/index.js +40 -3
- package/dist/esm/ipc-client.js +2 -2
- package/dist/esm/memory/consolidation.js +206 -0
- package/dist/esm/memory/extraction.js +185 -0
- package/dist/esm/memory/index.js +26 -0
- package/dist/esm/memory/retrieval.js +243 -0
- package/dist/esm/memory/types.js +72 -0
- package/dist/esm/namespace.js +262 -0
- package/dist/esm/queue.js +291 -0
- package/dist/esm/semantic-cache.js +223 -0
- package/dist/types/context-builder.d.ts +97 -0
- package/dist/types/context-builder.d.ts.map +1 -0
- package/dist/types/database.d.ts +1 -1
- package/dist/types/embedded/database.d.ts +1 -1
- package/dist/types/errors.d.ts +57 -1
- package/dist/types/errors.d.ts.map +1 -1
- package/dist/types/index.d.ts +12 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/ipc-client.d.ts +1 -1
- package/dist/types/memory/consolidation.d.ts +66 -0
- package/dist/types/memory/consolidation.d.ts.map +1 -0
- package/dist/types/memory/extraction.d.ts +82 -0
- package/dist/types/memory/extraction.d.ts.map +1 -0
- package/dist/types/memory/index.d.ts +10 -0
- package/dist/types/memory/index.d.ts.map +1 -0
- package/dist/types/memory/retrieval.d.ts +46 -0
- package/dist/types/memory/retrieval.d.ts.map +1 -0
- package/dist/types/memory/types.d.ts +147 -0
- package/dist/types/memory/types.d.ts.map +1 -0
- package/dist/types/namespace.d.ts +129 -0
- package/dist/types/namespace.d.ts.map +1 -0
- package/dist/types/queue.d.ts +120 -0
- package/dist/types/queue.d.ts.map +1 -0
- package/dist/types/semantic-cache.d.ts +84 -0
- package/dist/types/semantic-cache.d.ts.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Semantic Cache for LLM responses
|
|
4
|
+
*
|
|
5
|
+
* Cache LLM responses with similarity-based retrieval for cost savings.
|
|
6
|
+
* Uses database prefix scanning to store and retrieve cached responses.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.SemanticCache = void 0;
|
|
10
|
+
/**
|
|
11
|
+
* Calculate cosine similarity between two vectors
|
|
12
|
+
*/
|
|
13
|
+
function cosineSimilarity(a, b) {
|
|
14
|
+
if (a.length !== b.length) {
|
|
15
|
+
throw new Error('Vectors must have same length');
|
|
16
|
+
}
|
|
17
|
+
let dotProduct = 0;
|
|
18
|
+
let normA = 0;
|
|
19
|
+
let normB = 0;
|
|
20
|
+
for (let i = 0; i < a.length; i++) {
|
|
21
|
+
dotProduct += a[i] * b[i];
|
|
22
|
+
normA += a[i] * a[i];
|
|
23
|
+
normB += b[i] * b[i];
|
|
24
|
+
}
|
|
25
|
+
if (normA === 0 || normB === 0) {
|
|
26
|
+
return 0;
|
|
27
|
+
}
|
|
28
|
+
return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Semantic Cache with vector similarity matching
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* const cache = new SemanticCache(db, 'llm_responses');
|
|
36
|
+
*
|
|
37
|
+
* // Store response
|
|
38
|
+
* await cache.put(
|
|
39
|
+
* 'What is Python?',
|
|
40
|
+
* 'Python is a high-level programming language...',
|
|
41
|
+
* embedding,
|
|
42
|
+
* 3600 // TTL in seconds
|
|
43
|
+
* );
|
|
44
|
+
*
|
|
45
|
+
* // Check cache
|
|
46
|
+
* const hit = await cache.get(queryEmbedding, 0.85);
|
|
47
|
+
* if (hit) {
|
|
48
|
+
* console.log(`Cache HIT: ${hit.value} (similarity: ${hit.score})`);
|
|
49
|
+
* }
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
class SemanticCache {
|
|
53
|
+
constructor(db, cacheName) {
|
|
54
|
+
this.hits = 0;
|
|
55
|
+
this.misses = 0;
|
|
56
|
+
this.db = db;
|
|
57
|
+
this.cacheName = cacheName;
|
|
58
|
+
this.prefix = Buffer.from(`cache:${cacheName}:`);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Store a cached response
|
|
62
|
+
*/
|
|
63
|
+
async put(key, value, embedding, ttlSeconds = 0, metadata) {
|
|
64
|
+
const entry = {
|
|
65
|
+
key,
|
|
66
|
+
value,
|
|
67
|
+
embedding,
|
|
68
|
+
timestamp: Date.now(),
|
|
69
|
+
ttl: ttlSeconds > 0 ? ttlSeconds : undefined,
|
|
70
|
+
metadata,
|
|
71
|
+
};
|
|
72
|
+
const entryKey = Buffer.concat([
|
|
73
|
+
this.prefix,
|
|
74
|
+
Buffer.from(key),
|
|
75
|
+
]);
|
|
76
|
+
await this.db.put(entryKey, Buffer.from(JSON.stringify(entry)));
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Retrieve cached response by similarity
|
|
80
|
+
*
|
|
81
|
+
* @param queryEmbedding - Query embedding vector
|
|
82
|
+
* @param threshold - Minimum cosine similarity (0-1)
|
|
83
|
+
* @returns Best matching cache entry or null
|
|
84
|
+
*/
|
|
85
|
+
async get(queryEmbedding, threshold = 0.85) {
|
|
86
|
+
const now = Date.now();
|
|
87
|
+
let bestMatch = null;
|
|
88
|
+
let bestScore = threshold;
|
|
89
|
+
// Scan all cache entries with this prefix
|
|
90
|
+
try {
|
|
91
|
+
for await (const [_, valueBuffer] of this.db.scanPrefix(this.prefix)) {
|
|
92
|
+
const entry = JSON.parse(valueBuffer.toString());
|
|
93
|
+
// Check TTL expiration
|
|
94
|
+
if (entry.ttl && entry.timestamp) {
|
|
95
|
+
const expiresAt = entry.timestamp + entry.ttl * 1000;
|
|
96
|
+
if (now > expiresAt) {
|
|
97
|
+
continue; // Skip expired entries
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Calculate similarity
|
|
101
|
+
const score = cosineSimilarity(queryEmbedding, entry.embedding);
|
|
102
|
+
// Update best match
|
|
103
|
+
if (score > bestScore) {
|
|
104
|
+
bestScore = score;
|
|
105
|
+
bestMatch = { ...entry, score };
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
// If scan fails, return null
|
|
111
|
+
this.misses++;
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
if (bestMatch) {
|
|
115
|
+
this.hits++;
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
this.misses++;
|
|
119
|
+
}
|
|
120
|
+
return bestMatch;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Delete a specific cache entry
|
|
124
|
+
*/
|
|
125
|
+
async delete(key) {
|
|
126
|
+
const entryKey = Buffer.concat([
|
|
127
|
+
this.prefix,
|
|
128
|
+
Buffer.from(key),
|
|
129
|
+
]);
|
|
130
|
+
await this.db.delete(entryKey);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Clear all entries in this cache
|
|
134
|
+
*/
|
|
135
|
+
async clear() {
|
|
136
|
+
let deleted = 0;
|
|
137
|
+
try {
|
|
138
|
+
const toDelete = [];
|
|
139
|
+
for await (const [key] of this.db.scanPrefix(this.prefix)) {
|
|
140
|
+
toDelete.push(key);
|
|
141
|
+
}
|
|
142
|
+
for (const key of toDelete) {
|
|
143
|
+
await this.db.delete(key);
|
|
144
|
+
deleted++;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
// If operation fails, return count so far
|
|
149
|
+
return deleted;
|
|
150
|
+
}
|
|
151
|
+
// Reset stats
|
|
152
|
+
this.hits = 0;
|
|
153
|
+
this.misses = 0;
|
|
154
|
+
return deleted;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Get cache statistics
|
|
158
|
+
*/
|
|
159
|
+
async stats() {
|
|
160
|
+
const now = Date.now();
|
|
161
|
+
let count = 0;
|
|
162
|
+
let memoryUsage = 0;
|
|
163
|
+
try {
|
|
164
|
+
for await (const [key, value] of this.db.scanPrefix(this.prefix)) {
|
|
165
|
+
const entry = JSON.parse(value.toString());
|
|
166
|
+
// Skip expired entries
|
|
167
|
+
if (entry.ttl && entry.timestamp) {
|
|
168
|
+
const expiresAt = entry.timestamp + entry.ttl * 1000;
|
|
169
|
+
if (now > expiresAt) {
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
count++;
|
|
174
|
+
memoryUsage += key.length + value.length;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
// Return partial stats if operation fails
|
|
179
|
+
}
|
|
180
|
+
const total = this.hits + this.misses;
|
|
181
|
+
const hitRate = total > 0 ? this.hits / total : 0;
|
|
182
|
+
return {
|
|
183
|
+
count,
|
|
184
|
+
hits: this.hits,
|
|
185
|
+
misses: this.misses,
|
|
186
|
+
hitRate,
|
|
187
|
+
memoryUsage,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Purge expired entries
|
|
192
|
+
*/
|
|
193
|
+
async purgeExpired() {
|
|
194
|
+
const now = Date.now();
|
|
195
|
+
let purged = 0;
|
|
196
|
+
try {
|
|
197
|
+
const toDelete = [];
|
|
198
|
+
for await (const [key, value] of this.db.scanPrefix(this.prefix)) {
|
|
199
|
+
const entry = JSON.parse(value.toString());
|
|
200
|
+
if (entry.ttl && entry.timestamp) {
|
|
201
|
+
const expiresAt = entry.timestamp + entry.ttl * 1000;
|
|
202
|
+
if (now > expiresAt) {
|
|
203
|
+
toDelete.push(key);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
for (const key of toDelete) {
|
|
208
|
+
await this.db.delete(key);
|
|
209
|
+
purged++;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
// Return count so far
|
|
214
|
+
return purged;
|
|
215
|
+
}
|
|
216
|
+
return purged;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
exports.SemanticCache = SemanticCache;
|
|
220
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VtYW50aWMtY2FjaGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VtYW50aWMtY2FjaGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7OztHQUtHOzs7QUFJSDs7R0FFRztBQUNILFNBQVMsZ0JBQWdCLENBQUMsQ0FBVyxFQUFFLENBQVc7SUFDaEQsSUFBSSxDQUFDLENBQUMsTUFBTSxLQUFLLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUMxQixNQUFNLElBQUksS0FBSyxDQUFDLCtCQUErQixDQUFDLENBQUM7SUFDbkQsQ0FBQztJQUVELElBQUksVUFBVSxHQUFHLENBQUMsQ0FBQztJQUNuQixJQUFJLEtBQUssR0FBRyxDQUFDLENBQUM7SUFDZCxJQUFJLEtBQUssR0FBRyxDQUFDLENBQUM7SUFFZCxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1FBQ2xDLFVBQVUsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzFCLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3JCLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3ZCLENBQUM7SUFFRCxJQUFJLEtBQUssS0FBSyxDQUFDLElBQUksS0FBSyxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQy9CLE9BQU8sQ0FBQyxDQUFDO0lBQ1gsQ0FBQztJQUVELE9BQU8sVUFBVSxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7QUFDNUQsQ0FBQztBQXVCRDs7Ozs7Ozs7Ozs7Ozs7Ozs7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ME1DIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBTZW1hbnRpYyBDYWNoZSBmb3IgTExNIHJlc3BvbnNlc1xuICogXG4gKiBDYWNoZSBMTE0gcmVzcG9uc2VzIHdpdGggc2ltaWxhcml0eS1iYXNlZCByZXRyaWV2YWwgZm9yIGNvc3Qgc2F2aW5ncy5cbiAqIFVzZXMgZGF0YWJhc2UgcHJlZml4IHNjYW5uaW5nIHRvIHN0b3JlIGFuZCByZXRyaWV2ZSBjYWNoZWQgcmVzcG9uc2VzLlxuICovXG5cbmltcG9ydCB7IEVtYmVkZGVkRGF0YWJhc2UgfSBmcm9tICcuL2VtYmVkZGVkJztcblxuLyoqXG4gKiBDYWxjdWxhdGUgY29zaW5lIHNpbWlsYXJpdHkgYmV0d2VlbiB0d28gdmVjdG9yc1xuICovXG5mdW5jdGlvbiBjb3NpbmVTaW1pbGFyaXR5KGE6IG51bWJlcltdLCBiOiBudW1iZXJbXSk6IG51bWJlciB7XG4gIGlmIChhLmxlbmd0aCAhPT0gYi5sZW5ndGgpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ1ZlY3RvcnMgbXVzdCBoYXZlIHNhbWUgbGVuZ3RoJyk7XG4gIH1cblxuICBsZXQgZG90UHJvZHVjdCA9IDA7XG4gIGxldCBub3JtQSA9IDA7XG4gIGxldCBub3JtQiA9IDA7XG5cbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBhLmxlbmd0aDsgaSsrKSB7XG4gICAgZG90UHJvZHVjdCArPSBhW2ldICogYltpXTtcbiAgICBub3JtQSArPSBhW2ldICogYVtpXTtcbiAgICBub3JtQiArPSBiW2ldICogYltpXTtcbiAgfVxuXG4gIGlmIChub3JtQSA9PT0gMCB8fCBub3JtQiA9PT0gMCkge1xuICAgIHJldHVybiAwO1xuICB9XG5cbiAgcmV0dXJuIGRvdFByb2R1Y3QgLyAoTWF0aC5zcXJ0KG5vcm1BKSAqIE1hdGguc3FydChub3JtQikpO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIENhY2hlRW50cnkge1xuICBrZXk6IHN0cmluZztcbiAgdmFsdWU6IHN0cmluZztcbiAgZW1iZWRkaW5nOiBudW1iZXJbXTtcbiAgdGltZXN0YW1wOiBudW1iZXI7XG4gIHR0bD86IG51bWJlcjtcbiAgbWV0YWRhdGE/OiBSZWNvcmQ8c3RyaW5nLCBhbnk+O1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIENhY2hlSGl0IGV4dGVuZHMgQ2FjaGVFbnRyeSB7XG4gIHNjb3JlOiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ2FjaGVTdGF0cyB7XG4gIGNvdW50OiBudW1iZXI7XG4gIGhpdHM6IG51bWJlcjtcbiAgbWlzc2VzOiBudW1iZXI7XG4gIGhpdFJhdGU6IG51bWJlcjtcbiAgbWVtb3J5VXNhZ2U6IG51bWJlcjtcbn1cblxuLyoqXG4gKiBTZW1hbnRpYyBDYWNoZSB3aXRoIHZlY3RvciBzaW1pbGFyaXR5IG1hdGNoaW5nXG4gKiBcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCBjYWNoZSA9IG5ldyBTZW1hbnRpY0NhY2hlKGRiLCAnbGxtX3Jlc3BvbnNlcycpO1xuICogXG4gKiAvLyBTdG9yZSByZXNwb25zZVxuICogYXdhaXQgY2FjaGUucHV0KFxuICogICAnV2hhdCBpcyBQeXRob24/JyxcbiAqICAgJ1B5dGhvbiBpcyBhIGhpZ2gtbGV2ZWwgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2UuLi4nLFxuICogICBlbWJlZGRpbmcsXG4gKiAgIDM2MDAgIC8vIFRUTCBpbiBzZWNvbmRzXG4gKiApO1xuICogXG4gKiAvLyBDaGVjayBjYWNoZVxuICogY29uc3QgaGl0ID0gYXdhaXQgY2FjaGUuZ2V0KHF1ZXJ5RW1iZWRkaW5nLCAwLjg1KTtcbiAqIGlmIChoaXQpIHtcbiAqICAgY29uc29sZS5sb2coYENhY2hlIEhJVDogJHtoaXQudmFsdWV9IChzaW1pbGFyaXR5OiAke2hpdC5zY29yZX0pYCk7XG4gKiB9XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGNsYXNzIFNlbWFudGljQ2FjaGUge1xuICBwcml2YXRlIGRiOiBFbWJlZGRlZERhdGFiYXNlO1xuICBwcml2YXRlIGNhY2hlTmFtZTogc3RyaW5nO1xuICBwcml2YXRlIHByZWZpeDogQnVmZmVyO1xuICBwcml2YXRlIGhpdHMgPSAwO1xuICBwcml2YXRlIG1pc3NlcyA9IDA7XG5cbiAgY29uc3RydWN0b3IoZGI6IEVtYmVkZGVkRGF0YWJhc2UsIGNhY2hlTmFtZTogc3RyaW5nKSB7XG4gICAgdGhpcy5kYiA9IGRiO1xuICAgIHRoaXMuY2FjaGVOYW1lID0gY2FjaGVOYW1lO1xuICAgIHRoaXMucHJlZml4ID0gQnVmZmVyLmZyb20oYGNhY2hlOiR7Y2FjaGVOYW1lfTpgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdG9yZSBhIGNhY2hlZCByZXNwb25zZVxuICAgKi9cbiAgYXN5bmMgcHV0KFxuICAgIGtleTogc3RyaW5nLFxuICAgIHZhbHVlOiBzdHJpbmcsXG4gICAgZW1iZWRkaW5nOiBudW1iZXJbXSxcbiAgICB0dGxTZWNvbmRzID0gMCxcbiAgICBtZXRhZGF0YT86IFJlY29yZDxzdHJpbmcsIGFueT5cbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgZW50cnk6IENhY2hlRW50cnkgPSB7XG4gICAgICBrZXksXG4gICAgICB2YWx1ZSxcbiAgICAgIGVtYmVkZGluZyxcbiAgICAgIHRpbWVzdGFtcDogRGF0ZS5ub3coKSxcbiAgICAgIHR0bDogdHRsU2Vjb25kcyA+IDAgPyB0dGxTZWNvbmRzIDogdW5kZWZpbmVkLFxuICAgICAgbWV0YWRhdGEsXG4gICAgfTtcblxuICAgIGNvbnN0IGVudHJ5S2V5ID0gQnVmZmVyLmNvbmNhdChbXG4gICAgICB0aGlzLnByZWZpeCxcbiAgICAgIEJ1ZmZlci5mcm9tKGtleSksXG4gICAgXSk7XG5cbiAgICBhd2FpdCB0aGlzLmRiLnB1dChlbnRyeUtleSwgQnVmZmVyLmZyb20oSlNPTi5zdHJpbmdpZnkoZW50cnkpKSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0cmlldmUgY2FjaGVkIHJlc3BvbnNlIGJ5IHNpbWlsYXJpdHlcbiAgICogXG4gICAqIEBwYXJhbSBxdWVyeUVtYmVkZGluZyAtIFF1ZXJ5IGVtYmVkZGluZyB2ZWN0b3JcbiAgICogQHBhcmFtIHRocmVzaG9sZCAtIE1pbmltdW0gY29zaW5lIHNpbWlsYXJpdHkgKDAtMSlcbiAgICogQHJldHVybnMgQmVzdCBtYXRjaGluZyBjYWNoZSBlbnRyeSBvciBudWxsXG4gICAqL1xuICBhc3luYyBnZXQoXG4gICAgcXVlcnlFbWJlZGRpbmc6IG51bWJlcltdLFxuICAgIHRocmVzaG9sZCA9IDAuODVcbiAgKTogUHJvbWlzZTxDYWNoZUhpdCB8IG51bGw+IHtcbiAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICAgIGxldCBiZXN0TWF0Y2g6IENhY2hlSGl0IHwgbnVsbCA9IG51bGw7XG4gICAgbGV0IGJlc3RTY29yZSA9IHRocmVzaG9sZDtcblxuICAgIC8vIFNjYW4gYWxsIGNhY2hlIGVudHJpZXMgd2l0aCB0aGlzIHByZWZpeFxuICAgIHRyeSB7XG4gICAgICBmb3IgYXdhaXQgKGNvbnN0IFtfLCB2YWx1ZUJ1ZmZlcl0gb2YgdGhpcy5kYi5zY2FuUHJlZml4KHRoaXMucHJlZml4KSkge1xuICAgICAgICBjb25zdCBlbnRyeTogQ2FjaGVFbnRyeSA9IEpTT04ucGFyc2UodmFsdWVCdWZmZXIudG9TdHJpbmcoKSk7XG5cbiAgICAgICAgLy8gQ2hlY2sgVFRMIGV4cGlyYXRpb25cbiAgICAgICAgaWYgKGVudHJ5LnR0bCAmJiBlbnRyeS50aW1lc3RhbXApIHtcbiAgICAgICAgICBjb25zdCBleHBpcmVzQXQgPSBlbnRyeS50aW1lc3RhbXAgKyBlbnRyeS50dGwgKiAxMDAwO1xuICAgICAgICAgIGlmIChub3cgPiBleHBpcmVzQXQpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlOyAvLyBTa2lwIGV4cGlyZWQgZW50cmllc1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIENhbGN1bGF0ZSBzaW1pbGFyaXR5XG4gICAgICAgIGNvbnN0IHNjb3JlID0gY29zaW5lU2ltaWxhcml0eShxdWVyeUVtYmVkZGluZywgZW50cnkuZW1iZWRkaW5nKTtcblxuICAgICAgICAvLyBVcGRhdGUgYmVzdCBtYXRjaFxuICAgICAgICBpZiAoc2NvcmUgPiBiZXN0U2NvcmUpIHtcbiAgICAgICAgICBiZXN0U2NvcmUgPSBzY29yZTtcbiAgICAgICAgICBiZXN0TWF0Y2ggPSB7IC4uLmVudHJ5LCBzY29yZSB9O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIC8vIElmIHNjYW4gZmFpbHMsIHJldHVybiBudWxsXG4gICAgICB0aGlzLm1pc3NlcysrO1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgaWYgKGJlc3RNYXRjaCkge1xuICAgICAgdGhpcy5oaXRzKys7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMubWlzc2VzKys7XG4gICAgfVxuXG4gICAgcmV0dXJuIGJlc3RNYXRjaDtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWxldGUgYSBzcGVjaWZpYyBjYWNoZSBlbnRyeVxuICAgKi9cbiAgYXN5bmMgZGVsZXRlKGtleTogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgZW50cnlLZXkgPSBCdWZmZXIuY29uY2F0KFtcbiAgICAgIHRoaXMucHJlZml4LFxuICAgICAgQnVmZmVyLmZyb20oa2V5KSxcbiAgICBdKTtcbiAgICBhd2FpdCB0aGlzLmRiLmRlbGV0ZShlbnRyeUtleSk7XG4gIH1cblxuICAvKipcbiAgICogQ2xlYXIgYWxsIGVudHJpZXMgaW4gdGhpcyBjYWNoZVxuICAgKi9cbiAgYXN5bmMgY2xlYXIoKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBsZXQgZGVsZXRlZCA9IDA7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgdG9EZWxldGU6IEJ1ZmZlcltdID0gW107XG4gICAgICBmb3IgYXdhaXQgKGNvbnN0IFtrZXldIG9mIHRoaXMuZGIuc2NhblByZWZpeCh0aGlzLnByZWZpeCkpIHtcbiAgICAgICAgdG9EZWxldGUucHVzaChrZXkpO1xuICAgICAgfVxuXG4gICAgICBmb3IgKGNvbnN0IGtleSBvZiB0b0RlbGV0ZSkge1xuICAgICAgICBhd2FpdCB0aGlzLmRiLmRlbGV0ZShrZXkpO1xuICAgICAgICBkZWxldGVkKys7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIC8vIElmIG9wZXJhdGlvbiBmYWlscywgcmV0dXJuIGNvdW50IHNvIGZhclxuICAgICAgcmV0dXJuIGRlbGV0ZWQ7XG4gICAgfVxuXG4gICAgLy8gUmVzZXQgc3RhdHNcbiAgICB0aGlzLmhpdHMgPSAwO1xuICAgIHRoaXMubWlzc2VzID0gMDtcblxuICAgIHJldHVybiBkZWxldGVkO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBjYWNoZSBzdGF0aXN0aWNzXG4gICAqL1xuICBhc3luYyBzdGF0cygpOiBQcm9taXNlPENhY2hlU3RhdHM+IHtcbiAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICAgIGxldCBjb3VudCA9IDA7XG4gICAgbGV0IG1lbW9yeVVzYWdlID0gMDtcblxuICAgIHRyeSB7XG4gICAgICBmb3IgYXdhaXQgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiB0aGlzLmRiLnNjYW5QcmVmaXgodGhpcy5wcmVmaXgpKSB7XG4gICAgICAgIGNvbnN0IGVudHJ5OiBDYWNoZUVudHJ5ID0gSlNPTi5wYXJzZSh2YWx1ZS50b1N0cmluZygpKTtcbiAgICAgICAgXG4gICAgICAgIC8vIFNraXAgZXhwaXJlZCBlbnRyaWVzXG4gICAgICAgIGlmIChlbnRyeS50dGwgJiYgZW50cnkudGltZXN0YW1wKSB7XG4gICAgICAgICAgY29uc3QgZXhwaXJlc0F0ID0gZW50cnkudGltZXN0YW1wICsgZW50cnkudHRsICogMTAwMDtcbiAgICAgICAgICBpZiAobm93ID4gZXhwaXJlc0F0KSB7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBjb3VudCsrO1xuICAgICAgICBtZW1vcnlVc2FnZSArPSBrZXkubGVuZ3RoICsgdmFsdWUubGVuZ3RoO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAvLyBSZXR1cm4gcGFydGlhbCBzdGF0cyBpZiBvcGVyYXRpb24gZmFpbHNcbiAgICB9XG5cbiAgICBjb25zdCB0b3RhbCA9IHRoaXMuaGl0cyArIHRoaXMubWlzc2VzO1xuICAgIGNvbnN0IGhpdFJhdGUgPSB0b3RhbCA+IDAgPyB0aGlzLmhpdHMgLyB0b3RhbCA6IDA7XG5cbiAgICByZXR1cm4ge1xuICAgICAgY291bnQsXG4gICAgICBoaXRzOiB0aGlzLmhpdHMsXG4gICAgICBtaXNzZXM6IHRoaXMubWlzc2VzLFxuICAgICAgaGl0UmF0ZSxcbiAgICAgIG1lbW9yeVVzYWdlLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogUHVyZ2UgZXhwaXJlZCBlbnRyaWVzXG4gICAqL1xuICBhc3luYyBwdXJnZUV4cGlyZWQoKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICAgIGxldCBwdXJnZWQgPSAwO1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHRvRGVsZXRlOiBCdWZmZXJbXSA9IFtdO1xuXG4gICAgICBmb3IgYXdhaXQgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiB0aGlzLmRiLnNjYW5QcmVmaXgodGhpcy5wcmVmaXgpKSB7XG4gICAgICAgIGNvbnN0IGVudHJ5OiBDYWNoZUVudHJ5ID0gSlNPTi5wYXJzZSh2YWx1ZS50b1N0cmluZygpKTtcbiAgICAgICAgXG4gICAgICAgIGlmIChlbnRyeS50dGwgJiYgZW50cnkudGltZXN0YW1wKSB7XG4gICAgICAgICAgY29uc3QgZXhwaXJlc0F0ID0gZW50cnkudGltZXN0YW1wICsgZW50cnkudHRsICogMTAwMDtcbiAgICAgICAgICBpZiAobm93ID4gZXhwaXJlc0F0KSB7XG4gICAgICAgICAgICB0b0RlbGV0ZS5wdXNoKGtleSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGZvciAoY29uc3Qga2V5IG9mIHRvRGVsZXRlKSB7XG4gICAgICAgIGF3YWl0IHRoaXMuZGIuZGVsZXRlKGtleSk7XG4gICAgICAgIHB1cmdlZCsrO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAvLyBSZXR1cm4gY291bnQgc28gZmFyXG4gICAgICByZXR1cm4gcHVyZ2VkO1xuICAgIH1cblxuICAgIHJldHVybiBwdXJnZWQ7XG4gIH1cbn1cbiJdfQ==
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Context Query Builder for LLM Context Assembly
|
|
4
|
+
*
|
|
5
|
+
* Token-aware context assembly with priority-based truncation.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.ContextQueryBuilder = exports.TruncationStrategy = exports.ContextOutputFormat = void 0;
|
|
9
|
+
exports.createContextBuilder = createContextBuilder;
|
|
10
|
+
var ContextOutputFormat;
|
|
11
|
+
(function (ContextOutputFormat) {
|
|
12
|
+
ContextOutputFormat["TOON"] = "toon";
|
|
13
|
+
ContextOutputFormat["JSON"] = "json";
|
|
14
|
+
ContextOutputFormat["MARKDOWN"] = "markdown";
|
|
15
|
+
})(ContextOutputFormat || (exports.ContextOutputFormat = ContextOutputFormat = {}));
|
|
16
|
+
var TruncationStrategy;
|
|
17
|
+
(function (TruncationStrategy) {
|
|
18
|
+
TruncationStrategy["TAIL_DROP"] = "tail_drop";
|
|
19
|
+
TruncationStrategy["HEAD_DROP"] = "head_drop";
|
|
20
|
+
TruncationStrategy["PROPORTIONAL"] = "proportional";
|
|
21
|
+
})(TruncationStrategy || (exports.TruncationStrategy = TruncationStrategy = {}));
|
|
22
|
+
/**
|
|
23
|
+
* Context Query Builder for assembling LLM context
|
|
24
|
+
*/
|
|
25
|
+
class ContextQueryBuilder {
|
|
26
|
+
sessionId;
|
|
27
|
+
tokenBudget = 4096;
|
|
28
|
+
format = ContextOutputFormat.TOON;
|
|
29
|
+
truncation = TruncationStrategy.TAIL_DROP;
|
|
30
|
+
sections = [];
|
|
31
|
+
currentSection;
|
|
32
|
+
/**
|
|
33
|
+
* Set session ID for context
|
|
34
|
+
*/
|
|
35
|
+
forSession(sessionId) {
|
|
36
|
+
this.sessionId = sessionId;
|
|
37
|
+
return this;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Set token budget
|
|
41
|
+
*/
|
|
42
|
+
withBudget(tokens) {
|
|
43
|
+
this.tokenBudget = tokens;
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Set output format
|
|
48
|
+
*/
|
|
49
|
+
setFormat(format) {
|
|
50
|
+
this.format = format;
|
|
51
|
+
return this;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Set truncation strategy
|
|
55
|
+
*/
|
|
56
|
+
setTruncation(strategy) {
|
|
57
|
+
this.truncation = strategy;
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Add literal text section
|
|
62
|
+
*/
|
|
63
|
+
literal(name, priority, text) {
|
|
64
|
+
const tokenCount = this.estimateTokens(text);
|
|
65
|
+
this.sections.push({
|
|
66
|
+
name,
|
|
67
|
+
priority,
|
|
68
|
+
content: text,
|
|
69
|
+
tokenCount,
|
|
70
|
+
});
|
|
71
|
+
return this;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Start a new section
|
|
75
|
+
*/
|
|
76
|
+
section(name, priority) {
|
|
77
|
+
this.currentSection = {
|
|
78
|
+
name,
|
|
79
|
+
priority,
|
|
80
|
+
content: '',
|
|
81
|
+
tokenCount: 0,
|
|
82
|
+
};
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Add content to current section
|
|
87
|
+
*/
|
|
88
|
+
get(path) {
|
|
89
|
+
if (!this.currentSection) {
|
|
90
|
+
throw new Error('No active section. Call section() first.');
|
|
91
|
+
}
|
|
92
|
+
this.currentSection.content += `GET ${path}\n`;
|
|
93
|
+
return this;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Add last N records query
|
|
97
|
+
*/
|
|
98
|
+
last(n, table) {
|
|
99
|
+
if (!this.currentSection) {
|
|
100
|
+
throw new Error('No active section. Call section() first.');
|
|
101
|
+
}
|
|
102
|
+
this.currentSection.content += `LAST ${n} FROM ${table}\n`;
|
|
103
|
+
return this;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Add where equals condition
|
|
107
|
+
*/
|
|
108
|
+
whereEq(field, value) {
|
|
109
|
+
if (!this.currentSection) {
|
|
110
|
+
throw new Error('No active section. Call section() first.');
|
|
111
|
+
}
|
|
112
|
+
this.currentSection.content += `WHERE ${field} = ${JSON.stringify(value)}\n`;
|
|
113
|
+
return this;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Add vector search
|
|
117
|
+
*/
|
|
118
|
+
search(collection, embedding, k) {
|
|
119
|
+
if (!this.currentSection) {
|
|
120
|
+
throw new Error('No active section. Call section() first.');
|
|
121
|
+
}
|
|
122
|
+
this.currentSection.content += `SEARCH ${collection} WITH ${embedding} LIMIT ${k}\n`;
|
|
123
|
+
return this;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Add SQL query
|
|
127
|
+
*/
|
|
128
|
+
sql(query) {
|
|
129
|
+
if (!this.currentSection) {
|
|
130
|
+
throw new Error('No active section. Call section() first.');
|
|
131
|
+
}
|
|
132
|
+
this.currentSection.content += `SQL: ${query}\n`;
|
|
133
|
+
return this;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Finish current section
|
|
137
|
+
*/
|
|
138
|
+
done() {
|
|
139
|
+
if (this.currentSection) {
|
|
140
|
+
this.currentSection.tokenCount = this.estimateTokens(this.currentSection.content);
|
|
141
|
+
this.sections.push(this.currentSection);
|
|
142
|
+
this.currentSection = undefined;
|
|
143
|
+
}
|
|
144
|
+
return this;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Execute and build context
|
|
148
|
+
*/
|
|
149
|
+
execute() {
|
|
150
|
+
// Finish any pending section
|
|
151
|
+
if (this.currentSection) {
|
|
152
|
+
this.done();
|
|
153
|
+
}
|
|
154
|
+
// Sort sections by priority (lower = higher priority)
|
|
155
|
+
const sortedSections = [...this.sections].sort((a, b) => a.priority - b.priority);
|
|
156
|
+
// Calculate total tokens
|
|
157
|
+
let totalTokens = sortedSections.reduce((sum, s) => sum + s.tokenCount, 0);
|
|
158
|
+
// Truncate if needed
|
|
159
|
+
const truncatedSections = [];
|
|
160
|
+
const includedSections = [];
|
|
161
|
+
if (totalTokens <= this.tokenBudget) {
|
|
162
|
+
// No truncation needed
|
|
163
|
+
for (const section of sortedSections) {
|
|
164
|
+
includedSections.push(section);
|
|
165
|
+
truncatedSections.push({
|
|
166
|
+
name: section.name,
|
|
167
|
+
tokenCount: section.tokenCount,
|
|
168
|
+
truncated: false,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
// Apply truncation strategy
|
|
174
|
+
let remainingBudget = this.tokenBudget;
|
|
175
|
+
if (this.truncation === TruncationStrategy.TAIL_DROP) {
|
|
176
|
+
// Include sections in priority order until budget exhausted
|
|
177
|
+
for (const section of sortedSections) {
|
|
178
|
+
if (section.tokenCount <= remainingBudget) {
|
|
179
|
+
includedSections.push(section);
|
|
180
|
+
remainingBudget -= section.tokenCount;
|
|
181
|
+
truncatedSections.push({
|
|
182
|
+
name: section.name,
|
|
183
|
+
tokenCount: section.tokenCount,
|
|
184
|
+
truncated: false,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
truncatedSections.push({
|
|
189
|
+
name: section.name,
|
|
190
|
+
tokenCount: 0,
|
|
191
|
+
truncated: true,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
else if (this.truncation === TruncationStrategy.PROPORTIONAL) {
|
|
197
|
+
// Proportionally reduce all sections
|
|
198
|
+
const ratio = this.tokenBudget / totalTokens;
|
|
199
|
+
for (const section of sortedSections) {
|
|
200
|
+
const allocatedTokens = Math.floor(section.tokenCount * ratio);
|
|
201
|
+
const truncatedContent = this.truncateText(section.content, allocatedTokens);
|
|
202
|
+
includedSections.push({
|
|
203
|
+
...section,
|
|
204
|
+
content: truncatedContent,
|
|
205
|
+
tokenCount: allocatedTokens,
|
|
206
|
+
});
|
|
207
|
+
truncatedSections.push({
|
|
208
|
+
name: section.name,
|
|
209
|
+
tokenCount: allocatedTokens,
|
|
210
|
+
truncated: allocatedTokens < section.tokenCount,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
// Build final context based on format
|
|
216
|
+
let text = '';
|
|
217
|
+
let actualTokens = 0;
|
|
218
|
+
if (this.format === ContextOutputFormat.TOON) {
|
|
219
|
+
text = this.buildToonFormat(includedSections);
|
|
220
|
+
}
|
|
221
|
+
else if (this.format === ContextOutputFormat.JSON) {
|
|
222
|
+
text = this.buildJsonFormat(includedSections);
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
text = this.buildMarkdownFormat(includedSections);
|
|
226
|
+
}
|
|
227
|
+
actualTokens = this.estimateTokens(text);
|
|
228
|
+
return {
|
|
229
|
+
text,
|
|
230
|
+
tokenCount: actualTokens,
|
|
231
|
+
sections: truncatedSections,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
// Helper methods
|
|
235
|
+
estimateTokens(text) {
|
|
236
|
+
// Rough estimate: ~4 characters per token for English
|
|
237
|
+
return Math.ceil(text.length / 4);
|
|
238
|
+
}
|
|
239
|
+
truncateText(text, maxTokens) {
|
|
240
|
+
const maxChars = maxTokens * 4;
|
|
241
|
+
if (text.length <= maxChars) {
|
|
242
|
+
return text;
|
|
243
|
+
}
|
|
244
|
+
return text.substring(0, maxChars) + '...';
|
|
245
|
+
}
|
|
246
|
+
buildToonFormat(sections) {
|
|
247
|
+
const lines = [];
|
|
248
|
+
for (const section of sections) {
|
|
249
|
+
lines.push(`[${section.name}]`);
|
|
250
|
+
lines.push(section.content);
|
|
251
|
+
lines.push('');
|
|
252
|
+
}
|
|
253
|
+
return lines.join('\n');
|
|
254
|
+
}
|
|
255
|
+
buildJsonFormat(sections) {
|
|
256
|
+
const obj = {};
|
|
257
|
+
for (const section of sections) {
|
|
258
|
+
obj[section.name] = section.content;
|
|
259
|
+
}
|
|
260
|
+
return JSON.stringify(obj, null, 2);
|
|
261
|
+
}
|
|
262
|
+
buildMarkdownFormat(sections) {
|
|
263
|
+
const lines = [];
|
|
264
|
+
for (const section of sections) {
|
|
265
|
+
lines.push(`## ${section.name}`);
|
|
266
|
+
lines.push('');
|
|
267
|
+
lines.push(section.content);
|
|
268
|
+
lines.push('');
|
|
269
|
+
}
|
|
270
|
+
return lines.join('\n');
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
exports.ContextQueryBuilder = ContextQueryBuilder;
|
|
274
|
+
/**
|
|
275
|
+
* Create a context query builder
|
|
276
|
+
*/
|
|
277
|
+
function createContextBuilder() {
|
|
278
|
+
return new ContextQueryBuilder();
|
|
279
|
+
}
|
|
280
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udGV4dC1idWlsZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbnRleHQtYnVpbGRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7R0FJRzs7O0FBc1RILG9EQUVDO0FBdFRELElBQVksbUJBSVg7QUFKRCxXQUFZLG1CQUFtQjtJQUM3QixvQ0FBYSxDQUFBO0lBQ2Isb0NBQWEsQ0FBQTtJQUNiLDRDQUFxQixDQUFBO0FBQ3ZCLENBQUMsRUFKVyxtQkFBbUIsbUNBQW5CLG1CQUFtQixRQUk5QjtBQUVELElBQVksa0JBSVg7QUFKRCxXQUFZLGtCQUFrQjtJQUM1Qiw2Q0FBdUIsQ0FBQTtJQUN2Qiw2Q0FBdUIsQ0FBQTtJQUN2QixtREFBNkIsQ0FBQTtBQUMvQixDQUFDLEVBSlcsa0JBQWtCLGtDQUFsQixrQkFBa0IsUUFJN0I7QUFlRDs7R0FFRztBQUNILE1BQWEsbUJBQW1CO0lBQ3RCLFNBQVMsQ0FBVTtJQUNuQixXQUFXLEdBQVcsSUFBSSxDQUFDO0lBQzNCLE1BQU0sR0FBd0IsbUJBQW1CLENBQUMsSUFBSSxDQUFDO0lBQ3ZELFVBQVUsR0FBdUIsa0JBQWtCLENBQUMsU0FBUyxDQUFDO0lBQzlELFFBQVEsR0FBYyxFQUFFLENBQUM7SUFDekIsY0FBYyxDQUFXO0lBRWpDOztPQUVHO0lBQ0gsVUFBVSxDQUFDLFNBQWlCO1FBQzFCLElBQUksQ0FBQyxTQUFTLEdBQUcsU0FBUyxDQUFDO1FBQzNCLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVEOztPQUVHO0lBQ0gsVUFBVSxDQUFDLE1BQWM7UUFDdkIsSUFBSSxDQUFDLFdBQVcsR0FBRyxNQUFNLENBQUM7UUFDMUIsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxTQUFTLENBQUMsTUFBMkI7UUFDbkMsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7UUFDckIsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxhQUFhLENBQUMsUUFBNEI7UUFDeEMsSUFBSSxDQUFDLFVBQVUsR0FBRyxRQUFRLENBQUM7UUFDM0IsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxPQUFPLENBQUMsSUFBWSxFQUFFLFFBQWdCLEVBQUUsSUFBWTtRQUNsRCxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzdDLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDO1lBQ2pCLElBQUk7WUFDSixRQUFRO1lBQ1IsT0FBTyxFQUFFLElBQUk7WUFDYixVQUFVO1NBQ1gsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxPQUFPLENBQUMsSUFBWSxFQUFFLFFBQWdCO1FBQ3BDLElBQUksQ0FBQyxjQUFjLEdBQUc7WUFDcEIsSUFBSTtZQUNKLFFBQVE7WUFDUixPQUFPLEVBQUUsRUFBRTtZQUNYLFVBQVUsRUFBRSxDQUFDO1NBQ2QsQ0FBQztRQUNGLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVEOztPQUVHO0lBQ0gsR0FBRyxDQUFDLElBQVk7UUFDZCxJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ3pCLE1BQU0sSUFBSSxLQUFLLENBQUMsMENBQTBDLENBQUMsQ0FBQztRQUM5RCxDQUFDO1FBQ0QsSUFBSSxDQUFDLGNBQWMsQ0FBQyxPQUFPLElBQUksT0FBTyxJQUFJLElBQUksQ0FBQztRQUMvQyxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRDs7T0FFRztJQUNILElBQUksQ0FBQyxDQUFTLEVBQUUsS0FBYTtRQUMzQixJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ3pCLE1BQU0sSUFBSSxLQUFLLENBQUMsMENBQTBDLENBQUMsQ0FBQztRQUM5RCxDQUFDO1FBQ0QsSUFBSSxDQUFDLGNBQWMsQ0FBQyxPQUFPLElBQUksUUFBUSxDQUFDLFNBQVMsS0FBSyxJQUFJLENBQUM7UUFDM0QsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxPQUFPLENBQUMsS0FBYSxFQUFFLEtBQVU7UUFDL0IsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUN6QixNQUFNLElBQUksS0FBSyxDQUFDLDBDQUEwQyxDQUFDLENBQUM7UUFDOUQsQ0FBQztRQUNELElBQUksQ0FBQyxjQUFjLENBQUMsT0FBTyxJQUFJLFNBQVMsS0FBSyxNQUFNLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQztRQUM3RSxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRDs7T0FFRztJQUNILE1BQU0sQ0FBQyxVQUFrQixFQUFFLFNBQWlCLEVBQUUsQ0FBUztRQUNyRCxJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ3pCLE1BQU0sSUFBSSxLQUFLLENBQUMsMENBQTBDLENBQUMsQ0FBQztRQUM5RCxDQUFDO1FBQ0QsSUFBSSxDQUFDLGNBQWMsQ0FBQyxPQUFPLElBQUksVUFBVSxVQUFVLFNBQVMsU0FBUyxVQUFVLENBQUMsSUFBSSxDQUFDO1FBQ3JGLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVEOztPQUVHO0lBQ0gsR0FBRyxDQUFDLEtBQWE7UUFDZixJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ3pCLE1BQU0sSUFBSSxLQUFLLENBQUMsMENBQTBDLENBQUMsQ0FBQztRQUM5RCxDQUFDO1FBQ0QsSUFBSSxDQUFDLGNBQWMsQ0FBQyxPQUFPLElBQUksUUFBUSxLQUFLLElBQUksQ0FBQztRQUNqRCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRDs7T0FFRztJQUNILElBQUk7UUFDRixJQUFJLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUN4QixJQUFJLENBQUMsY0FBYyxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDbEYsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1lBQ3hDLElBQUksQ0FBQyxjQUFjLEdBQUcsU0FBUyxDQUFDO1FBQ2xDLENBQUM7UUFDRCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRDs7T0FFRztJQUNILE9BQU87UUFDTCw2QkFBNkI7UUFDN0IsSUFBSSxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7WUFDeEIsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ2QsQ0FBQztRQUVELHNEQUFzRDtRQUN0RCxNQUFNLGNBQWMsR0FBRyxDQUFDLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxRQUFRLEdBQUcsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBRWxGLHlCQUF5QjtRQUN6QixJQUFJLFdBQVcsR0FBRyxjQUFjLENBQUMsTUFBTSxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFFM0UscUJBQXFCO1FBQ3JCLE1BQU0saUJBQWlCLEdBQW9FLEVBQUUsQ0FBQztRQUM5RixNQUFNLGdCQUFnQixHQUFjLEVBQUUsQ0FBQztRQUV2QyxJQUFJLFdBQVcsSUFBSSxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDcEMsdUJBQXVCO1lBQ3ZCLEtBQUssTUFBTSxPQUFPLElBQUksY0FBYyxFQUFFLENBQUM7Z0JBQ3JDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztnQkFDL0IsaUJBQWlCLENBQUMsSUFBSSxDQUFDO29CQUNyQixJQUFJLEVBQUUsT0FBTyxDQUFDLElBQUk7b0JBQ2xCLFVBQVUsRUFBRSxPQUFPLENBQUMsVUFBVTtvQkFDOUIsU0FBUyxFQUFFLEtBQUs7aUJBQ2pCLENBQUMsQ0FBQztZQUNMLENBQUM7UUFDSCxDQUFDO2FBQU0sQ0FBQztZQUNOLDRCQUE0QjtZQUM1QixJQUFJLGVBQWUsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDO1lBRXZDLElBQUksSUFBSSxDQUFDLFVBQVUsS0FBSyxrQkFBa0IsQ0FBQyxTQUFTLEVBQUUsQ0FBQztnQkFDckQsNERBQTREO2dCQUM1RCxLQUFLLE1BQU0sT0FBTyxJQUFJLGNBQWMsRUFBRSxDQUFDO29CQUNyQyxJQUFJLE9BQU8sQ0FBQyxVQUFVLElBQUksZUFBZSxFQUFFLENBQUM7d0JBQzFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQzt3QkFDL0IsZUFBZSxJQUFJLE9BQU8sQ0FBQyxVQUFVLENBQUM7d0JBQ3RDLGlCQUFpQixDQUFDLElBQUksQ0FBQzs0QkFDckIsSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJOzRCQUNsQixVQUFVLEVBQUUsT0FBTyxDQUFDLFVBQVU7NEJBQzlCLFNBQVMsRUFBRSxLQUFLO3lCQUNqQixDQUFDLENBQUM7b0JBQ0wsQ0FBQzt5QkFBTSxDQUFDO3dCQUNOLGlCQUFpQixDQUFDLElBQUksQ0FBQzs0QkFDckIsSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJOzRCQUNsQixVQUFVLEVBQUUsQ0FBQzs0QkFDYixTQUFTLEVBQUUsSUFBSTt5QkFDaEIsQ0FBQyxDQUFDO29CQUNMLENBQUM7Z0JBQ0gsQ0FBQztZQUNILENBQUM7aUJBQU0sSUFBSSxJQUFJLENBQUMsVUFBVSxLQUFLLGtCQUFrQixDQUFDLFlBQVksRUFBRSxDQUFDO2dCQUMvRCxxQ0FBcUM7Z0JBQ3JDLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxXQUFXLEdBQUcsV0FBVyxDQUFDO2dCQUM3QyxLQUFLLE1BQU0sT0FBTyxJQUFJLGNBQWMsRUFBRSxDQUFDO29CQUNyQyxNQUFNLGVBQWUsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxVQUFVLEdBQUcsS0FBSyxDQUFDLENBQUM7b0JBQy9ELE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLGVBQWUsQ0FBQyxDQUFDO29CQUM3RSxnQkFBZ0IsQ0FBQyxJQUFJLENBQUM7d0JBQ3BCLEdBQUcsT0FBTzt3QkFDVixPQUFPLEVBQUUsZ0JBQWdCO3dCQUN6QixVQUFVLEVBQUUsZUFBZTtxQkFDNUIsQ0FBQyxDQUFDO29CQUNILGlCQUFpQixDQUFDLElBQUksQ0FBQzt3QkFDckIsSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJO3dCQUNsQixVQUFVLEVBQUUsZUFBZTt3QkFDM0IsU0FBUyxFQUFFLGVBQWUsR0FBRyxPQUFPLENBQUMsVUFBVTtxQkFDaEQsQ0FBQyxDQUFDO2dCQUNMLENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQztRQUVELHNDQUFzQztRQUN0QyxJQUFJLElBQUksR0FBRyxFQUFFLENBQUM7UUFDZCxJQUFJLFlBQVksR0FBRyxDQUFDLENBQUM7UUFFckIsSUFBSSxJQUFJLENBQUMsTUFBTSxLQUFLLG1CQUFtQixDQUFDLElBQUksRUFBRSxDQUFDO1lBQzdDLElBQUksR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLGdCQUFnQixDQUFDLENBQUM7UUFDaEQsQ0FBQzthQUFNLElBQUksSUFBSSxDQUFDLE1BQU0sS0FBSyxtQkFBbUIsQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNwRCxJQUFJLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBQ2hELENBQUM7YUFBTSxDQUFDO1lBQ04sSUFBSSxHQUFHLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBQ3BELENBQUM7UUFFRCxZQUFZLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUV6QyxPQUFPO1lBQ0wsSUFBSTtZQUNKLFVBQVUsRUFBRSxZQUFZO1lBQ3hCLFFBQVEsRUFBRSxpQkFBaUI7U0FDNUIsQ0FBQztJQUNKLENBQUM7SUFFRCxpQkFBaUI7SUFDVCxjQUFjLENBQUMsSUFBWTtRQUNqQyxzREFBc0Q7UUFDdEQsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDcEMsQ0FBQztJQUVPLFlBQVksQ0FBQyxJQUFZLEVBQUUsU0FBaUI7UUFDbEQsTUFBTSxRQUFRLEdBQUcsU0FBUyxHQUFHLENBQUMsQ0FBQztRQUMvQixJQUFJLElBQUksQ0FBQyxNQUFNLElBQUksUUFBUSxFQUFFLENBQUM7WUFDNUIsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxRQUFRLENBQUMsR0FBRyxLQUFLLENBQUM7SUFDN0MsQ0FBQztJQUVPLGVBQWUsQ0FBQyxRQUFtQjtRQUN6QyxNQUFNLEtBQUssR0FBYSxFQUFFLENBQUM7UUFFM0IsS0FBSyxNQUFNLE9BQU8sSUFBSSxRQUFRLEVBQUUsQ0FBQztZQUMvQixLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksT0FBTyxDQUFDLElBQUksR0FBRyxDQUFDLENBQUM7WUFDaEMsS0FBSyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDNUIsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNqQixDQUFDO1FBRUQsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzFCLENBQUM7SUFFTyxlQUFlLENBQUMsUUFBbUI7UUFDekMsTUFBTSxHQUFHLEdBQTJCLEVBQUUsQ0FBQztRQUV2QyxLQUFLLE1BQU0sT0FBTyxJQUFJLFFBQVEsRUFBRSxDQUFDO1lBQy9CLEdBQUcsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQztRQUN0QyxDQUFDO1FBRUQsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDdEMsQ0FBQztJQUVPLG1CQUFtQixDQUFDLFFBQW1CO1FBQzdDLE1BQU0sS0FBSyxHQUFhLEVBQUUsQ0FBQztRQUUzQixLQUFLLE1BQU0sT0FBTyxJQUFJLFFBQVEsRUFBRSxDQUFDO1lBQy9CLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztZQUNqQyxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ2YsS0FBSyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDNUIsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNqQixDQUFDO1FBRUQsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzFCLENBQUM7Q0FDRjtBQW5SRCxrREFtUkM7QUFFRDs7R0FFRztBQUNILFNBQWdCLG9CQUFvQjtJQUNsQyxPQUFPLElBQUksbUJBQW1CLEVBQUUsQ0FBQztBQUNuQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDb250ZXh0IFF1ZXJ5IEJ1aWxkZXIgZm9yIExMTSBDb250ZXh0IEFzc2VtYmx5XG4gKiBcbiAqIFRva2VuLWF3YXJlIGNvbnRleHQgYXNzZW1ibHkgd2l0aCBwcmlvcml0eS1iYXNlZCB0cnVuY2F0aW9uLlxuICovXG5cbmV4cG9ydCBlbnVtIENvbnRleHRPdXRwdXRGb3JtYXQge1xuICBUT09OID0gJ3Rvb24nLFxuICBKU09OID0gJ2pzb24nLFxuICBNQVJLRE9XTiA9ICdtYXJrZG93bicsXG59XG5cbmV4cG9ydCBlbnVtIFRydW5jYXRpb25TdHJhdGVneSB7XG4gIFRBSUxfRFJPUCA9ICd0YWlsX2Ryb3AnLCAgICAgICAvLyBEcm9wIGZyb20gZW5kXG4gIEhFQURfRFJPUCA9ICdoZWFkX2Ryb3AnLCAgICAgICAvLyBEcm9wIGZyb20gYmVnaW5uaW5nXG4gIFBST1BPUlRJT05BTCA9ICdwcm9wb3J0aW9uYWwnLCAvLyBQcm9wb3J0aW9uYWwgYWNyb3NzIHNlY3Rpb25zXG59XG5cbmludGVyZmFjZSBTZWN0aW9uIHtcbiAgbmFtZTogc3RyaW5nO1xuICBwcmlvcml0eTogbnVtYmVyO1xuICBjb250ZW50OiBzdHJpbmc7XG4gIHRva2VuQ291bnQ6IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDb250ZXh0UmVzdWx0IHtcbiAgdGV4dDogc3RyaW5nO1xuICB0b2tlbkNvdW50OiBudW1iZXI7XG4gIHNlY3Rpb25zOiBBcnJheTx7IG5hbWU6IHN0cmluZzsgdG9rZW5Db3VudDogbnVtYmVyOyB0cnVuY2F0ZWQ6IGJvb2xlYW4gfT47XG59XG5cbi8qKlxuICogQ29udGV4dCBRdWVyeSBCdWlsZGVyIGZvciBhc3NlbWJsaW5nIExMTSBjb250ZXh0XG4gKi9cbmV4cG9ydCBjbGFzcyBDb250ZXh0UXVlcnlCdWlsZGVyIHtcbiAgcHJpdmF0ZSBzZXNzaW9uSWQ/OiBzdHJpbmc7XG4gIHByaXZhdGUgdG9rZW5CdWRnZXQ6IG51bWJlciA9IDQwOTY7XG4gIHByaXZhdGUgZm9ybWF0OiBDb250ZXh0T3V0cHV0Rm9ybWF0ID0gQ29udGV4dE91dHB1dEZvcm1hdC5UT09OO1xuICBwcml2YXRlIHRydW5jYXRpb246IFRydW5jYXRpb25TdHJhdGVneSA9IFRydW5jYXRpb25TdHJhdGVneS5UQUlMX0RST1A7XG4gIHByaXZhdGUgc2VjdGlvbnM6IFNlY3Rpb25bXSA9IFtdO1xuICBwcml2YXRlIGN1cnJlbnRTZWN0aW9uPzogU2VjdGlvbjtcblxuICAvKipcbiAgICogU2V0IHNlc3Npb24gSUQgZm9yIGNvbnRleHRcbiAgICovXG4gIGZvclNlc3Npb24oc2Vzc2lvbklkOiBzdHJpbmcpOiB0aGlzIHtcbiAgICB0aGlzLnNlc3Npb25JZCA9IHNlc3Npb25JZDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXQgdG9rZW4gYnVkZ2V0XG4gICAqL1xuICB3aXRoQnVkZ2V0KHRva2VuczogbnVtYmVyKTogdGhpcyB7XG4gICAgdGhpcy50b2tlbkJ1ZGdldCA9IHRva2VucztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXQgb3V0cHV0IGZvcm1hdFxuICAgKi9cbiAgc2V0Rm9ybWF0KGZvcm1hdDogQ29udGV4dE91dHB1dEZvcm1hdCk6IHRoaXMge1xuICAgIHRoaXMuZm9ybWF0ID0gZm9ybWF0O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldCB0cnVuY2F0aW9uIHN0cmF0ZWd5XG4gICAqL1xuICBzZXRUcnVuY2F0aW9uKHN0cmF0ZWd5OiBUcnVuY2F0aW9uU3RyYXRlZ3kpOiB0aGlzIHtcbiAgICB0aGlzLnRydW5jYXRpb24gPSBzdHJhdGVneTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgbGl0ZXJhbCB0ZXh0IHNlY3Rpb25cbiAgICovXG4gIGxpdGVyYWwobmFtZTogc3RyaW5nLCBwcmlvcml0eTogbnVtYmVyLCB0ZXh0OiBzdHJpbmcpOiB0aGlzIHtcbiAgICBjb25zdCB0b2tlbkNvdW50ID0gdGhpcy5lc3RpbWF0ZVRva2Vucyh0ZXh0KTtcbiAgICB0aGlzLnNlY3Rpb25zLnB1c2goe1xuICAgICAgbmFtZSxcbiAgICAgIHByaW9yaXR5LFxuICAgICAgY29udGVudDogdGV4dCxcbiAgICAgIHRva2VuQ291bnQsXG4gICAgfSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogU3RhcnQgYSBuZXcgc2VjdGlvblxuICAgKi9cbiAgc2VjdGlvbihuYW1lOiBzdHJpbmcsIHByaW9yaXR5OiBudW1iZXIpOiB0aGlzIHtcbiAgICB0aGlzLmN1cnJlbnRTZWN0aW9uID0ge1xuICAgICAgbmFtZSxcbiAgICAgIHByaW9yaXR5LFxuICAgICAgY29udGVudDogJycsXG4gICAgICB0b2tlbkNvdW50OiAwLFxuICAgIH07XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQWRkIGNvbnRlbnQgdG8gY3VycmVudCBzZWN0aW9uXG4gICAqL1xuICBnZXQocGF0aDogc3RyaW5nKTogdGhpcyB7XG4gICAgaWYgKCF0aGlzLmN1cnJlbnRTZWN0aW9uKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIGFjdGl2ZSBzZWN0aW9uLiBDYWxsIHNlY3Rpb24oKSBmaXJzdC4nKTtcbiAgICB9XG4gICAgdGhpcy5jdXJyZW50U2VjdGlvbi5jb250ZW50ICs9IGBHRVQgJHtwYXRofVxcbmA7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQWRkIGxhc3QgTiByZWNvcmRzIHF1ZXJ5XG4gICAqL1xuICBsYXN0KG46IG51bWJlciwgdGFibGU6IHN0cmluZyk6IHRoaXMge1xuICAgIGlmICghdGhpcy5jdXJyZW50U2VjdGlvbikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBhY3RpdmUgc2VjdGlvbi4gQ2FsbCBzZWN0aW9uKCkgZmlyc3QuJyk7XG4gICAgfVxuICAgIHRoaXMuY3VycmVudFNlY3Rpb24uY29udGVudCArPSBgTEFTVCAke259IEZST00gJHt0YWJsZX1cXG5gO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZCB3aGVyZSBlcXVhbHMgY29uZGl0aW9uXG4gICAqL1xuICB3aGVyZUVxKGZpZWxkOiBzdHJpbmcsIHZhbHVlOiBhbnkpOiB0aGlzIHtcbiAgICBpZiAoIXRoaXMuY3VycmVudFNlY3Rpb24pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignTm8gYWN0aXZlIHNlY3Rpb24uIENhbGwgc2VjdGlvbigpIGZpcnN0LicpO1xuICAgIH1cbiAgICB0aGlzLmN1cnJlbnRTZWN0aW9uLmNvbnRlbnQgKz0gYFdIRVJFICR7ZmllbGR9ID0gJHtKU09OLnN0cmluZ2lmeSh2YWx1ZSl9XFxuYDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgdmVjdG9yIHNlYXJjaFxuICAgKi9cbiAgc2VhcmNoKGNvbGxlY3Rpb246IHN0cmluZywgZW1iZWRkaW5nOiBzdHJpbmcsIGs6IG51bWJlcik6IHRoaXMge1xuICAgIGlmICghdGhpcy5jdXJyZW50U2VjdGlvbikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBhY3RpdmUgc2VjdGlvbi4gQ2FsbCBzZWN0aW9uKCkgZmlyc3QuJyk7XG4gICAgfVxuICAgIHRoaXMuY3VycmVudFNlY3Rpb24uY29udGVudCArPSBgU0VBUkNIICR7Y29sbGVjdGlvbn0gV0lUSCAke2VtYmVkZGluZ30gTElNSVQgJHtrfVxcbmA7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQWRkIFNRTCBxdWVyeVxuICAgKi9cbiAgc3FsKHF1ZXJ5OiBzdHJpbmcpOiB0aGlzIHtcbiAgICBpZiAoIXRoaXMuY3VycmVudFNlY3Rpb24pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignTm8gYWN0aXZlIHNlY3Rpb24uIENhbGwgc2VjdGlvbigpIGZpcnN0LicpO1xuICAgIH1cbiAgICB0aGlzLmN1cnJlbnRTZWN0aW9uLmNvbnRlbnQgKz0gYFNRTDogJHtxdWVyeX1cXG5gO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEZpbmlzaCBjdXJyZW50IHNlY3Rpb25cbiAgICovXG4gIGRvbmUoKTogdGhpcyB7XG4gICAgaWYgKHRoaXMuY3VycmVudFNlY3Rpb24pIHtcbiAgICAgIHRoaXMuY3VycmVudFNlY3Rpb24udG9rZW5Db3VudCA9IHRoaXMuZXN0aW1hdGVUb2tlbnModGhpcy5jdXJyZW50U2VjdGlvbi5jb250ZW50KTtcbiAgICAgIHRoaXMuc2VjdGlvbnMucHVzaCh0aGlzLmN1cnJlbnRTZWN0aW9uKTtcbiAgICAgIHRoaXMuY3VycmVudFNlY3Rpb24gPSB1bmRlZmluZWQ7XG4gICAgfVxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEV4ZWN1dGUgYW5kIGJ1aWxkIGNvbnRleHRcbiAgICovXG4gIGV4ZWN1dGUoKTogQ29udGV4dFJlc3VsdCB7XG4gICAgLy8gRmluaXNoIGFueSBwZW5kaW5nIHNlY3Rpb25cbiAgICBpZiAodGhpcy5jdXJyZW50U2VjdGlvbikge1xuICAgICAgdGhpcy5kb25lKCk7XG4gICAgfVxuXG4gICAgLy8gU29ydCBzZWN0aW9ucyBieSBwcmlvcml0eSAobG93ZXIgPSBoaWdoZXIgcHJpb3JpdHkpXG4gICAgY29uc3Qgc29ydGVkU2VjdGlvbnMgPSBbLi4udGhpcy5zZWN0aW9uc10uc29ydCgoYSwgYikgPT4gYS5wcmlvcml0eSAtIGIucHJpb3JpdHkpO1xuXG4gICAgLy8gQ2FsY3VsYXRlIHRvdGFsIHRva2Vuc1xuICAgIGxldCB0b3RhbFRva2VucyA9IHNvcnRlZFNlY3Rpb25zLnJlZHVjZSgoc3VtLCBzKSA9PiBzdW0gKyBzLnRva2VuQ291bnQsIDApO1xuXG4gICAgLy8gVHJ1bmNhdGUgaWYgbmVlZGVkXG4gICAgY29uc3QgdHJ1bmNhdGVkU2VjdGlvbnM6IEFycmF5PHsgbmFtZTogc3RyaW5nOyB0b2tlbkNvdW50OiBudW1iZXI7IHRydW5jYXRlZDogYm9vbGVhbiB9PiA9IFtdO1xuICAgIGNvbnN0IGluY2x1ZGVkU2VjdGlvbnM6IFNlY3Rpb25bXSA9IFtdO1xuXG4gICAgaWYgKHRvdGFsVG9rZW5zIDw9IHRoaXMudG9rZW5CdWRnZXQpIHtcbiAgICAgIC8vIE5vIHRydW5jYXRpb24gbmVlZGVkXG4gICAgICBmb3IgKGNvbnN0IHNlY3Rpb24gb2Ygc29ydGVkU2VjdGlvbnMpIHtcbiAgICAgICAgaW5jbHVkZWRTZWN0aW9ucy5wdXNoKHNlY3Rpb24pO1xuICAgICAgICB0cnVuY2F0ZWRTZWN0aW9ucy5wdXNoKHtcbiAgICAgICAgICBuYW1lOiBzZWN0aW9uLm5hbWUsXG4gICAgICAgICAgdG9rZW5Db3VudDogc2VjdGlvbi50b2tlbkNvdW50LFxuICAgICAgICAgIHRydW5jYXRlZDogZmFsc2UsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICAvLyBBcHBseSB0cnVuY2F0aW9uIHN0cmF0ZWd5XG4gICAgICBsZXQgcmVtYWluaW5nQnVkZ2V0ID0gdGhpcy50b2tlbkJ1ZGdldDtcblxuICAgICAgaWYgKHRoaXMudHJ1bmNhdGlvbiA9PT0gVHJ1bmNhdGlvblN0cmF0ZWd5LlRBSUxfRFJPUCkge1xuICAgICAgICAvLyBJbmNsdWRlIHNlY3Rpb25zIGluIHByaW9yaXR5IG9yZGVyIHVudGlsIGJ1ZGdldCBleGhhdXN0ZWRcbiAgICAgICAgZm9yIChjb25zdCBzZWN0aW9uIG9mIHNvcnRlZFNlY3Rpb25zKSB7XG4gICAgICAgICAgaWYgKHNlY3Rpb24udG9rZW5Db3VudCA8PSByZW1haW5pbmdCdWRnZXQpIHtcbiAgICAgICAgICAgIGluY2x1ZGVkU2VjdGlvbnMucHVzaChzZWN0aW9uKTtcbiAgICAgICAgICAgIHJlbWFpbmluZ0J1ZGdldCAtPSBzZWN0aW9uLnRva2VuQ291bnQ7XG4gICAgICAgICAgICB0cnVuY2F0ZWRTZWN0aW9ucy5wdXNoKHtcbiAgICAgICAgICAgICAgbmFtZTogc2VjdGlvbi5uYW1lLFxuICAgICAgICAgICAgICB0b2tlbkNvdW50OiBzZWN0aW9uLnRva2VuQ291bnQsXG4gICAgICAgICAgICAgIHRydW5jYXRlZDogZmFsc2UsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdHJ1bmNhdGVkU2VjdGlvbnMucHVzaCh7XG4gICAgICAgICAgICAgIG5hbWU6IHNlY3Rpb24ubmFtZSxcbiAgICAgICAgICAgICAgdG9rZW5Db3VudDogMCxcbiAgICAgICAgICAgICAgdHJ1bmNhdGVkOiB0cnVlLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKHRoaXMudHJ1bmNhdGlvbiA9PT0gVHJ1bmNhdGlvblN0cmF0ZWd5LlBST1BPUlRJT05BTCkge1xuICAgICAgICAvLyBQcm9wb3J0aW9uYWxseSByZWR1Y2UgYWxsIHNlY3Rpb25zXG4gICAgICAgIGNvbnN0IHJhdGlvID0gdGhpcy50b2tlbkJ1ZGdldCAvIHRvdGFsVG9rZW5zO1xuICAgICAgICBmb3IgKGNvbnN0IHNlY3Rpb24gb2Ygc29ydGVkU2VjdGlvbnMpIHtcbiAgICAgICAgICBjb25zdCBhbGxvY2F0ZWRUb2tlbnMgPSBNYXRoLmZsb29yKHNlY3Rpb24udG9rZW5Db3VudCAqIHJhdGlvKTtcbiAgICAgICAgICBjb25zdCB0cnVuY2F0ZWRDb250ZW50ID0gdGhpcy50cnVuY2F0ZVRleHQoc2VjdGlvbi5jb250ZW50LCBhbGxvY2F0ZWRUb2tlbnMpO1xuICAgICAgICAgIGluY2x1ZGVkU2VjdGlvbnMucHVzaCh7XG4gICAgICAgICAgICAuLi5zZWN0aW9uLFxuICAgICAgICAgICAgY29udGVudDogdHJ1bmNhdGVkQ29udGVudCxcbiAgICAgICAgICAgIHRva2VuQ291bnQ6IGFsbG9jYXRlZFRva2VucyxcbiAgICAgICAgICB9KTtcbiAgICAgICAgICB0cnVuY2F0ZWRTZWN0aW9ucy5wdXNoKHtcbiAgICAgICAgICAgIG5hbWU6IHNlY3Rpb24ubmFtZSxcbiAgICAgICAgICAgIHRva2VuQ291bnQ6IGFsbG9jYXRlZFRva2VucyxcbiAgICAgICAgICAgIHRydW5jYXRlZDogYWxsb2NhdGVkVG9rZW5zIDwgc2VjdGlvbi50b2tlbkNvdW50LFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gQnVpbGQgZmluYWwgY29udGV4dCBiYXNlZCBvbiBmb3JtYXRcbiAgICBsZXQgdGV4dCA9ICcnO1xuICAgIGxldCBhY3R1YWxUb2tlbnMgPSAwO1xuXG4gICAgaWYgKHRoaXMuZm9ybWF0ID09PSBDb250ZXh0T3V0cHV0Rm9ybWF0LlRPT04pIHtcbiAgICAgIHRleHQgPSB0aGlzLmJ1aWxkVG9vbkZvcm1hdChpbmNsdWRlZFNlY3Rpb25zKTtcbiAgICB9IGVsc2UgaWYgKHRoaXMuZm9ybWF0ID09PSBDb250ZXh0T3V0cHV0Rm9ybWF0LkpTT04pIHtcbiAgICAgIHRleHQgPSB0aGlzLmJ1aWxkSnNvbkZvcm1hdChpbmNsdWRlZFNlY3Rpb25zKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGV4dCA9IHRoaXMuYnVpbGRNYXJrZG93bkZvcm1hdChpbmNsdWRlZFNlY3Rpb25zKTtcbiAgICB9XG5cbiAgICBhY3R1YWxUb2tlbnMgPSB0aGlzLmVzdGltYXRlVG9rZW5zKHRleHQpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHRleHQsXG4gICAgICB0b2tlbkNvdW50OiBhY3R1YWxUb2tlbnMsXG4gICAgICBzZWN0aW9uczogdHJ1bmNhdGVkU2VjdGlvbnMsXG4gICAgfTtcbiAgfVxuXG4gIC8vIEhlbHBlciBtZXRob2RzXG4gIHByaXZhdGUgZXN0aW1hdGVUb2tlbnModGV4dDogc3RyaW5nKTogbnVtYmVyIHtcbiAgICAvLyBSb3VnaCBlc3RpbWF0ZTogfjQgY2hhcmFjdGVycyBwZXIgdG9rZW4gZm9yIEVuZ2xpc2hcbiAgICByZXR1cm4gTWF0aC5jZWlsKHRleHQubGVuZ3RoIC8gNCk7XG4gIH1cblxuICBwcml2YXRlIHRydW5jYXRlVGV4dCh0ZXh0OiBzdHJpbmcsIG1heFRva2VuczogbnVtYmVyKTogc3RyaW5nIHtcbiAgICBjb25zdCBtYXhDaGFycyA9IG1heFRva2VucyAqIDQ7XG4gICAgaWYgKHRleHQubGVuZ3RoIDw9IG1heENoYXJzKSB7XG4gICAgICByZXR1cm4gdGV4dDtcbiAgICB9XG4gICAgcmV0dXJuIHRleHQuc3Vic3RyaW5nKDAsIG1heENoYXJzKSArICcuLi4nO1xuICB9XG5cbiAgcHJpdmF0ZSBidWlsZFRvb25Gb3JtYXQoc2VjdGlvbnM6IFNlY3Rpb25bXSk6IHN0cmluZyB7XG4gICAgY29uc3QgbGluZXM6IHN0cmluZ1tdID0gW107XG4gICAgXG4gICAgZm9yIChjb25zdCBzZWN0aW9uIG9mIHNlY3Rpb25zKSB7XG4gICAgICBsaW5lcy5wdXNoKGBbJHtzZWN0aW9uLm5hbWV9XWApO1xuICAgICAgbGluZXMucHVzaChzZWN0aW9uLmNvbnRlbnQpO1xuICAgICAgbGluZXMucHVzaCgnJyk7XG4gICAgfVxuICAgIFxuICAgIHJldHVybiBsaW5lcy5qb2luKCdcXG4nKTtcbiAgfVxuXG4gIHByaXZhdGUgYnVpbGRKc29uRm9ybWF0KHNlY3Rpb25zOiBTZWN0aW9uW10pOiBzdHJpbmcge1xuICAgIGNvbnN0IG9iajogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9O1xuICAgIFxuICAgIGZvciAoY29uc3Qgc2VjdGlvbiBvZiBzZWN0aW9ucykge1xuICAgICAgb2JqW3NlY3Rpb24ubmFtZV0gPSBzZWN0aW9uLmNvbnRlbnQ7XG4gICAgfVxuICAgIFxuICAgIHJldHVybiBKU09OLnN0cmluZ2lmeShvYmosIG51bGwsIDIpO1xuICB9XG5cbiAgcHJpdmF0ZSBidWlsZE1hcmtkb3duRm9ybWF0KHNlY3Rpb25zOiBTZWN0aW9uW10pOiBzdHJpbmcge1xuICAgIGNvbnN0IGxpbmVzOiBzdHJpbmdbXSA9IFtdO1xuICAgIFxuICAgIGZvciAoY29uc3Qgc2VjdGlvbiBvZiBzZWN0aW9ucykge1xuICAgICAgbGluZXMucHVzaChgIyMgJHtzZWN0aW9uLm5hbWV9YCk7XG4gICAgICBsaW5lcy5wdXNoKCcnKTtcbiAgICAgIGxpbmVzLnB1c2goc2VjdGlvbi5jb250ZW50KTtcbiAgICAgIGxpbmVzLnB1c2goJycpO1xuICAgIH1cbiAgICBcbiAgICByZXR1cm4gbGluZXMuam9pbignXFxuJyk7XG4gIH1cbn1cblxuLyoqXG4gKiBDcmVhdGUgYSBjb250ZXh0IHF1ZXJ5IGJ1aWxkZXJcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUNvbnRleHRCdWlsZGVyKCk6IENvbnRleHRRdWVyeUJ1aWxkZXIge1xuICByZXR1cm4gbmV3IENvbnRleHRRdWVyeUJ1aWxkZXIoKTtcbn1cbiJdfQ==
|