@psiclawops/hypermem 0.6.2 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +31 -39
- package/README.md +20 -14
- package/bin/hypermem-status.mjs +1 -1
- package/dist/background-indexer.d.ts +14 -3
- package/dist/background-indexer.d.ts.map +1 -1
- package/dist/background-indexer.js +135 -27
- package/dist/budget-policy.d.ts +22 -0
- package/dist/budget-policy.d.ts.map +1 -0
- package/dist/budget-policy.js +27 -0
- package/dist/cache.d.ts +11 -0
- package/dist/cache.d.ts.map +1 -1
- package/dist/compositor-utils.d.ts +31 -0
- package/dist/compositor-utils.d.ts.map +1 -0
- package/dist/compositor-utils.js +47 -0
- package/dist/compositor.d.ts +163 -1
- package/dist/compositor.d.ts.map +1 -1
- package/dist/compositor.js +862 -130
- package/dist/content-hash.d.ts +43 -0
- package/dist/content-hash.d.ts.map +1 -0
- package/dist/content-hash.js +75 -0
- package/dist/context-store.d.ts +54 -0
- package/dist/context-store.d.ts.map +1 -1
- package/dist/context-store.js +102 -0
- package/dist/contradiction-audit-store.d.ts +54 -0
- package/dist/contradiction-audit-store.d.ts.map +1 -0
- package/dist/contradiction-audit-store.js +88 -0
- package/dist/contradiction-detector.d.ts +78 -0
- package/dist/contradiction-detector.d.ts.map +1 -0
- package/dist/contradiction-detector.js +362 -0
- package/dist/contradiction-resolution-policy.d.ts +21 -0
- package/dist/contradiction-resolution-policy.d.ts.map +1 -0
- package/dist/contradiction-resolution-policy.js +17 -0
- package/dist/cross-agent.d.ts +1 -1
- package/dist/cross-agent.js +17 -17
- package/dist/degradation.d.ts +102 -0
- package/dist/degradation.d.ts.map +1 -0
- package/dist/degradation.js +141 -0
- package/dist/dreaming-promoter.d.ts +39 -1
- package/dist/dreaming-promoter.d.ts.map +1 -1
- package/dist/dreaming-promoter.js +70 -4
- package/dist/expertise-store.d.ts +129 -0
- package/dist/expertise-store.d.ts.map +1 -0
- package/dist/expertise-store.js +342 -0
- package/dist/fact-store.d.ts +15 -0
- package/dist/fact-store.d.ts.map +1 -1
- package/dist/fact-store.js +52 -5
- package/dist/index.d.ts +74 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +407 -29
- package/dist/knowledge-lint.d.ts +2 -0
- package/dist/knowledge-lint.d.ts.map +1 -1
- package/dist/knowledge-lint.js +40 -1
- package/dist/library-schema.d.ts +7 -2
- package/dist/library-schema.d.ts.map +1 -1
- package/dist/library-schema.js +307 -2
- package/dist/message-store.d.ts +64 -1
- package/dist/message-store.d.ts.map +1 -1
- package/dist/message-store.js +137 -1
- package/dist/proactive-pass.d.ts +2 -2
- package/dist/proactive-pass.d.ts.map +1 -1
- package/dist/proactive-pass.js +66 -12
- package/dist/replay-recovery.d.ts +29 -0
- package/dist/replay-recovery.d.ts.map +1 -0
- package/dist/replay-recovery.js +82 -0
- package/dist/reranker.d.ts +95 -0
- package/dist/reranker.d.ts.map +1 -0
- package/dist/reranker.js +308 -0
- package/dist/schema.d.ts +1 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +46 -1
- package/dist/seed.d.ts +1 -1
- package/dist/seed.js +1 -1
- package/dist/session-flusher.d.ts +4 -4
- package/dist/session-flusher.d.ts.map +1 -1
- package/dist/session-flusher.js +3 -3
- package/dist/spawn-context.d.ts +1 -1
- package/dist/spawn-context.js +1 -1
- package/dist/temporal-store.d.ts +1 -0
- package/dist/temporal-store.d.ts.map +1 -1
- package/dist/tool-artifact-store.d.ts +98 -0
- package/dist/tool-artifact-store.d.ts.map +1 -0
- package/dist/tool-artifact-store.js +244 -0
- package/dist/topic-detector.js +2 -2
- package/dist/topic-store.d.ts +6 -0
- package/dist/topic-store.d.ts.map +1 -1
- package/dist/topic-store.js +39 -0
- package/dist/topic-synthesizer.js +1 -1
- package/dist/trigger-registry.d.ts +1 -1
- package/dist/trigger-registry.js +4 -4
- package/dist/types.d.ts +239 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/vector-store.d.ts +2 -1
- package/dist/vector-store.d.ts.map +1 -1
- package/dist/vector-store.js +3 -0
- package/dist/version.d.ts +10 -10
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +10 -10
- package/package.json +6 -4
package/dist/reranker.js
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hypermem Reranker
|
|
3
|
+
*
|
|
4
|
+
* Pluggable reranking interface with circuit-breaker protection and graceful
|
|
5
|
+
* degradation. Callers that receive null fall back to the original document
|
|
6
|
+
* order without disruption.
|
|
7
|
+
*
|
|
8
|
+
* Providers:
|
|
9
|
+
* - ZeroEntropyReranker — https://api.zeroentropy.dev/v1/rerank (zerank-2)
|
|
10
|
+
* - OpenRouterReranker — https://openrouter.ai/api/v1/rerank (cohere/rerank-4-pro)
|
|
11
|
+
* - OllamaReranker — http://localhost:11434/api/chat (yes/no classification)
|
|
12
|
+
*
|
|
13
|
+
* API key resolution order (per provider):
|
|
14
|
+
* zeroentropy: config.zeroEntropyApiKey → ZEROENTROPY_API_KEY env var
|
|
15
|
+
* openrouter: config.openrouterApiKey → OPENROUTER_API_KEY env var
|
|
16
|
+
*/
|
|
17
|
+
// ── Circuit Breaker ───────────────────────────────────────────────────────────
|
|
18
|
+
/** Number of consecutive failures before the circuit opens. */
|
|
19
|
+
const CIRCUIT_FAILURE_THRESHOLD = 3;
|
|
20
|
+
/** How long the circuit stays open after tripping (ms). */
|
|
21
|
+
const CIRCUIT_DISABLE_DURATION_MS = 60_000;
|
|
22
|
+
/**
|
|
23
|
+
* CircuitBreaker protects a provider from repeated calls during sustained
|
|
24
|
+
* failures.
|
|
25
|
+
*
|
|
26
|
+
* State machine:
|
|
27
|
+
* CLOSED — normal operation; failures increment the counter.
|
|
28
|
+
* OPEN — provider disabled; isOpen() returns true for DISABLE_DURATION.
|
|
29
|
+
* HALF-OPEN — one probe allowed after the disable window expires;
|
|
30
|
+
* success resets the counter, failure re-opens the circuit.
|
|
31
|
+
*
|
|
32
|
+
* Transition: CLOSED → OPEN when consecutiveFailures >= FAILURE_THRESHOLD.
|
|
33
|
+
* Transition: OPEN → HALF-OPEN when Date.now() >= disabledUntil.
|
|
34
|
+
* Transition: HALF-OPEN → CLOSED on recordSuccess().
|
|
35
|
+
* Transition: HALF-OPEN → OPEN on recordFailure() (reset window starts fresh).
|
|
36
|
+
*/
|
|
37
|
+
class CircuitBreaker {
|
|
38
|
+
/** Consecutive failures since last success. Reset to 0 on any success. */
|
|
39
|
+
consecutiveFailures = 0;
|
|
40
|
+
/**
|
|
41
|
+
* Epoch ms after which the circuit allows a probe.
|
|
42
|
+
* 0 means the circuit is CLOSED (not disabled).
|
|
43
|
+
*/
|
|
44
|
+
disabledUntil = 0;
|
|
45
|
+
/** Returns true when the provider should be skipped. */
|
|
46
|
+
isOpen() {
|
|
47
|
+
if (this.disabledUntil === 0)
|
|
48
|
+
return false; // CLOSED
|
|
49
|
+
if (Date.now() >= this.disabledUntil) {
|
|
50
|
+
// Disable window expired — transition to HALF-OPEN: allow one probe.
|
|
51
|
+
// We clear disabledUntil here so the next call goes through.
|
|
52
|
+
// If it fails, recordFailure() re-opens the circuit with a fresh window.
|
|
53
|
+
this.disabledUntil = 0;
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
return true; // OPEN
|
|
57
|
+
}
|
|
58
|
+
/** Call on a successful provider response. Resets all failure state. */
|
|
59
|
+
recordSuccess() {
|
|
60
|
+
this.consecutiveFailures = 0;
|
|
61
|
+
this.disabledUntil = 0;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Call on any provider failure (non-2xx, timeout, parse error, etc.).
|
|
65
|
+
* After CIRCUIT_FAILURE_THRESHOLD consecutive failures, opens the circuit
|
|
66
|
+
* for CIRCUIT_DISABLE_DURATION_MS milliseconds.
|
|
67
|
+
*/
|
|
68
|
+
recordFailure() {
|
|
69
|
+
this.consecutiveFailures += 1;
|
|
70
|
+
if (this.consecutiveFailures >= CIRCUIT_FAILURE_THRESHOLD) {
|
|
71
|
+
// Trip the circuit — disable for the configured window.
|
|
72
|
+
// Reset consecutiveFailures so the probe after the window isn't
|
|
73
|
+
// pre-tripped by the old count.
|
|
74
|
+
this.disabledUntil = Date.now() + CIRCUIT_DISABLE_DURATION_MS;
|
|
75
|
+
this.consecutiveFailures = 0;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
80
|
+
/** Returns an AbortController that fires after `ms` and a cleanup handle. */
|
|
81
|
+
function withTimeout(ms) {
|
|
82
|
+
const controller = new AbortController();
|
|
83
|
+
const id = setTimeout(() => controller.abort(), ms);
|
|
84
|
+
return { controller, clear: () => clearTimeout(id) };
|
|
85
|
+
}
|
|
86
|
+
// ── ZeroEntropyReranker ───────────────────────────────────────────────────────
|
|
87
|
+
export class ZeroEntropyReranker {
|
|
88
|
+
name = 'zeroentropy';
|
|
89
|
+
circuit = new CircuitBreaker();
|
|
90
|
+
apiKey;
|
|
91
|
+
model;
|
|
92
|
+
timeoutMs;
|
|
93
|
+
constructor(apiKey, model = 'zerank-2', timeoutMs = 2000) {
|
|
94
|
+
this.apiKey = apiKey;
|
|
95
|
+
this.model = model;
|
|
96
|
+
this.timeoutMs = timeoutMs;
|
|
97
|
+
}
|
|
98
|
+
async rerank(query, documents, topK = 10) {
|
|
99
|
+
if (this.circuit.isOpen())
|
|
100
|
+
return null;
|
|
101
|
+
const { controller, clear } = withTimeout(this.timeoutMs);
|
|
102
|
+
try {
|
|
103
|
+
const response = await fetch('https://api.zeroentropy.dev/v1/rerank', {
|
|
104
|
+
method: 'POST',
|
|
105
|
+
headers: {
|
|
106
|
+
'Content-Type': 'application/json',
|
|
107
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
108
|
+
},
|
|
109
|
+
body: JSON.stringify({ query, documents, model: this.model, top_n: topK }),
|
|
110
|
+
signal: controller.signal,
|
|
111
|
+
});
|
|
112
|
+
clear();
|
|
113
|
+
if (!response.ok) {
|
|
114
|
+
this.circuit.recordFailure();
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
const data = (await response.json());
|
|
118
|
+
if (!Array.isArray(data.results)) {
|
|
119
|
+
this.circuit.recordFailure();
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
this.circuit.recordSuccess();
|
|
123
|
+
return data.results.map((r) => {
|
|
124
|
+
const score = r.score ?? r.relevance_score ?? 0;
|
|
125
|
+
const content = resolveDocumentText(r.content, r.document, documents[r.index]);
|
|
126
|
+
return { index: r.index, score, content };
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
clear();
|
|
131
|
+
this.circuit.recordFailure();
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// ── OpenRouterReranker ────────────────────────────────────────────────────────
|
|
137
|
+
export class OpenRouterReranker {
|
|
138
|
+
name = 'openrouter';
|
|
139
|
+
circuit = new CircuitBreaker();
|
|
140
|
+
apiKey;
|
|
141
|
+
model;
|
|
142
|
+
timeoutMs;
|
|
143
|
+
constructor(apiKey, model = 'cohere/rerank-4-pro', timeoutMs = 2000) {
|
|
144
|
+
this.apiKey = apiKey;
|
|
145
|
+
this.model = model;
|
|
146
|
+
this.timeoutMs = timeoutMs;
|
|
147
|
+
}
|
|
148
|
+
async rerank(query, documents, topK = 10) {
|
|
149
|
+
if (this.circuit.isOpen())
|
|
150
|
+
return null;
|
|
151
|
+
const { controller, clear } = withTimeout(this.timeoutMs);
|
|
152
|
+
try {
|
|
153
|
+
const response = await fetch('https://openrouter.ai/api/v1/rerank', {
|
|
154
|
+
method: 'POST',
|
|
155
|
+
headers: {
|
|
156
|
+
'Content-Type': 'application/json',
|
|
157
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
158
|
+
},
|
|
159
|
+
body: JSON.stringify({ query, documents, model: this.model, top_n: topK }),
|
|
160
|
+
signal: controller.signal,
|
|
161
|
+
});
|
|
162
|
+
clear();
|
|
163
|
+
if (!response.ok) {
|
|
164
|
+
this.circuit.recordFailure();
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
const data = (await response.json());
|
|
168
|
+
if (!Array.isArray(data.results)) {
|
|
169
|
+
this.circuit.recordFailure();
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
this.circuit.recordSuccess();
|
|
173
|
+
return data.results.map((r) => {
|
|
174
|
+
const score = r.relevance_score ?? r.score ?? 0;
|
|
175
|
+
const content = resolveDocumentText(undefined, r.document, documents[r.index]);
|
|
176
|
+
return { index: r.index, score, content };
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
clear();
|
|
181
|
+
this.circuit.recordFailure();
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
// ── OllamaReranker ────────────────────────────────────────────────────────────
|
|
187
|
+
const OLLAMA_SYSTEM_PROMPT = 'Judge whether the Document meets the requirements based on the Query and the Instruct provided. ' +
|
|
188
|
+
'Note that the answer can only be "yes" or "no".';
|
|
189
|
+
export class OllamaReranker {
|
|
190
|
+
name = 'ollama';
|
|
191
|
+
circuit = new CircuitBreaker();
|
|
192
|
+
baseUrl;
|
|
193
|
+
model;
|
|
194
|
+
timeoutMs;
|
|
195
|
+
constructor(baseUrl = 'http://localhost:11434', model = 'dengcao/Qwen3-Reranker-0.6B:Q5_K_M', timeoutMs = 10_000) {
|
|
196
|
+
this.baseUrl = baseUrl.replace(/\/$/, '');
|
|
197
|
+
this.model = model;
|
|
198
|
+
this.timeoutMs = timeoutMs;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Scores documents sequentially — one chat call per document.
|
|
202
|
+
* The Qwen3-Reranker-0.6B model responds with "yes" (relevant) or "no".
|
|
203
|
+
* Score: yes → 1.0, anything else → 0.0.
|
|
204
|
+
*
|
|
205
|
+
* Sequential iteration is required because Ollama's /api/chat is stateless
|
|
206
|
+
* per-request and running calls in parallel would overload a local GPU.
|
|
207
|
+
* Returns null on the first failure to preserve circuit breaker semantics.
|
|
208
|
+
*/
|
|
209
|
+
async rerank(query, documents, topK = 10) {
|
|
210
|
+
if (this.circuit.isOpen())
|
|
211
|
+
return null;
|
|
212
|
+
const scored = [];
|
|
213
|
+
for (let i = 0; i < documents.length; i++) {
|
|
214
|
+
const doc = documents[i];
|
|
215
|
+
const userContent = `Instruct: Given a query, retrieve relevant passages that answer the query\n\n` +
|
|
216
|
+
`Query: ${query}\n\nDocument: ${doc}`;
|
|
217
|
+
const { controller, clear } = withTimeout(this.timeoutMs);
|
|
218
|
+
try {
|
|
219
|
+
const response = await fetch(`${this.baseUrl}/api/chat`, {
|
|
220
|
+
method: 'POST',
|
|
221
|
+
headers: { 'Content-Type': 'application/json' },
|
|
222
|
+
body: JSON.stringify({
|
|
223
|
+
model: this.model,
|
|
224
|
+
messages: [
|
|
225
|
+
{ role: 'system', content: OLLAMA_SYSTEM_PROMPT },
|
|
226
|
+
{ role: 'user', content: userContent },
|
|
227
|
+
],
|
|
228
|
+
stream: false,
|
|
229
|
+
}),
|
|
230
|
+
signal: controller.signal,
|
|
231
|
+
});
|
|
232
|
+
clear();
|
|
233
|
+
if (!response.ok) {
|
|
234
|
+
this.circuit.recordFailure();
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
const data = (await response.json());
|
|
238
|
+
const answer = (data.message?.content ?? '').trim().toLowerCase();
|
|
239
|
+
// "yes" prefix → relevant; anything else (including "no") → not relevant
|
|
240
|
+
const score = answer.startsWith('yes') ? 1.0 : 0.0;
|
|
241
|
+
scored.push({ index: i, score, content: doc });
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
clear();
|
|
245
|
+
this.circuit.recordFailure();
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
this.circuit.recordSuccess();
|
|
250
|
+
// Sort by score descending and return top-K
|
|
251
|
+
scored.sort((a, b) => b.score - a.score);
|
|
252
|
+
return scored.slice(0, topK);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
// ── Factory ───────────────────────────────────────────────────────────────────
|
|
256
|
+
/**
|
|
257
|
+
* Creates a RerankerProvider from the supplied config.
|
|
258
|
+
*
|
|
259
|
+
* API key resolution order:
|
|
260
|
+
* zeroentropy: config.zeroEntropyApiKey → ZEROENTROPY_API_KEY env var
|
|
261
|
+
* openrouter: config.openrouterApiKey → OPENROUTER_API_KEY env var
|
|
262
|
+
*
|
|
263
|
+
* Returns null when:
|
|
264
|
+
* - provider is 'none'
|
|
265
|
+
* - provider is 'zeroentropy' and no key found in config or env
|
|
266
|
+
* - provider is 'openrouter' and no key found in config or env
|
|
267
|
+
*
|
|
268
|
+
* 'local' (Ollama) never returns null from the factory — it has no required
|
|
269
|
+
* API key. The provider itself returns null on runtime failure.
|
|
270
|
+
*/
|
|
271
|
+
export function createReranker(config) {
|
|
272
|
+
switch (config.provider) {
|
|
273
|
+
case 'none':
|
|
274
|
+
return null;
|
|
275
|
+
case 'zeroentropy': {
|
|
276
|
+
const apiKey = config.zeroEntropyApiKey ?? process.env['ZEROENTROPY_API_KEY'];
|
|
277
|
+
if (!apiKey)
|
|
278
|
+
return null;
|
|
279
|
+
return new ZeroEntropyReranker(apiKey, config.zeroEntropyModel ?? 'zerank-2', config.timeoutMs);
|
|
280
|
+
}
|
|
281
|
+
case 'openrouter': {
|
|
282
|
+
const apiKey = config.openrouterApiKey ?? process.env['OPENROUTER_API_KEY'];
|
|
283
|
+
if (!apiKey)
|
|
284
|
+
return null;
|
|
285
|
+
return new OpenRouterReranker(apiKey, config.openrouterModel ?? 'cohere/rerank-4-pro', config.timeoutMs);
|
|
286
|
+
}
|
|
287
|
+
case 'local': {
|
|
288
|
+
return new OllamaReranker(config.ollamaUrl ?? 'http://localhost:11434', config.ollamaModel ?? 'dengcao/Qwen3-Reranker-0.6B:Q5_K_M', config.timeoutMs);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
// ── Private Helpers ───────────────────────────────────────────────────────────
|
|
293
|
+
/**
|
|
294
|
+
* Resolves the document text from a reranking API response.
|
|
295
|
+
* Preference order: explicit `content` string → `document` string →
|
|
296
|
+
* `document.text` string → original document from the input array.
|
|
297
|
+
*/
|
|
298
|
+
function resolveDocumentText(content, document, fallback) {
|
|
299
|
+
if (typeof content === 'string')
|
|
300
|
+
return content;
|
|
301
|
+
if (typeof document === 'string')
|
|
302
|
+
return document;
|
|
303
|
+
if (document !== null && typeof document === 'object' && typeof document.text === 'string') {
|
|
304
|
+
return document.text;
|
|
305
|
+
}
|
|
306
|
+
return fallback ?? '';
|
|
307
|
+
}
|
|
308
|
+
//# sourceMappingURL=reranker.js.map
|
package/dist/schema.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Contains ONLY conversation data — structured knowledge lives in library.db.
|
|
7
7
|
*/
|
|
8
8
|
import type { DatabaseSync } from 'node:sqlite';
|
|
9
|
-
export declare const LATEST_SCHEMA_VERSION =
|
|
9
|
+
export declare const LATEST_SCHEMA_VERSION = 10;
|
|
10
10
|
/**
|
|
11
11
|
* Run migrations on an agent message database.
|
|
12
12
|
*/
|
package/dist/schema.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,eAAO,MAAM,qBAAqB,
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAgJxC;;GAEG;AACH,wBAAgB,OAAO,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CA0K9C;AAED,OAAO,EAAE,qBAAqB,IAAI,cAAc,EAAE,CAAC"}
|
package/dist/schema.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Write-heavy, temporal, rotatable.
|
|
6
6
|
* Contains ONLY conversation data — structured knowledge lives in library.db.
|
|
7
7
|
*/
|
|
8
|
-
export const LATEST_SCHEMA_VERSION =
|
|
8
|
+
export const LATEST_SCHEMA_VERSION = 10;
|
|
9
9
|
function nowIso() {
|
|
10
10
|
return new Date().toISOString();
|
|
11
11
|
}
|
|
@@ -250,6 +250,51 @@ export function migrate(db) {
|
|
|
250
250
|
db.prepare('INSERT OR IGNORE INTO schema_version (version, applied_at) VALUES (?, ?)')
|
|
251
251
|
.run(8, nowIso());
|
|
252
252
|
}
|
|
253
|
+
// v8 → v9: Tool Artifact Store — durable storage for full tool result payloads.
|
|
254
|
+
// Transcript stubs carry an artifactId pointer; raw payload lives here so
|
|
255
|
+
// wave-guard degradation is never lossy. See specs/TOOL_ARTIFACT_STORE.md.
|
|
256
|
+
if (currentVersion < 9) {
|
|
257
|
+
db.exec(`
|
|
258
|
+
CREATE TABLE IF NOT EXISTS tool_artifacts (
|
|
259
|
+
id TEXT PRIMARY KEY,
|
|
260
|
+
content_hash TEXT NOT NULL,
|
|
261
|
+
agent_id TEXT NOT NULL,
|
|
262
|
+
session_key TEXT NOT NULL,
|
|
263
|
+
conversation_id INTEGER REFERENCES conversations(id),
|
|
264
|
+
message_id INTEGER REFERENCES messages(id),
|
|
265
|
+
turn_id TEXT,
|
|
266
|
+
tool_call_id TEXT,
|
|
267
|
+
tool_name TEXT NOT NULL,
|
|
268
|
+
is_error INTEGER NOT NULL DEFAULT 0,
|
|
269
|
+
content_type TEXT NOT NULL DEFAULT 'text/plain',
|
|
270
|
+
size_bytes INTEGER NOT NULL,
|
|
271
|
+
token_estimate INTEGER NOT NULL,
|
|
272
|
+
payload TEXT NOT NULL,
|
|
273
|
+
summary TEXT,
|
|
274
|
+
created_at TEXT NOT NULL,
|
|
275
|
+
last_used_at TEXT NOT NULL,
|
|
276
|
+
ref_count INTEGER NOT NULL DEFAULT 1
|
|
277
|
+
)
|
|
278
|
+
`);
|
|
279
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_tool_artifacts_hash ON tool_artifacts(content_hash)');
|
|
280
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_tool_artifacts_session ON tool_artifacts(agent_id, session_key, created_at DESC)');
|
|
281
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_tool_artifacts_turn ON tool_artifacts(turn_id)');
|
|
282
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_tool_artifacts_tool_call ON tool_artifacts(tool_call_id)');
|
|
283
|
+
db.prepare('INSERT OR IGNORE INTO schema_version (version, applied_at) VALUES (?, ?)')
|
|
284
|
+
.run(9, nowIso());
|
|
285
|
+
}
|
|
286
|
+
// v9 → v10: Retention sweep — add is_sensitive flag to tool_artifacts.
|
|
287
|
+
// Enables differential TTL: sensitive artifacts expire sooner than standard ones.
|
|
288
|
+
// See: ToolArtifactStore.sweep() and ToolArtifactRetentionPolicy.
|
|
289
|
+
if (currentVersion < 10) {
|
|
290
|
+
const taCols = db.prepare('PRAGMA table_info(tool_artifacts)').all()
|
|
291
|
+
.map(r => r.name);
|
|
292
|
+
if (!taCols.includes('is_sensitive')) {
|
|
293
|
+
db.exec('ALTER TABLE tool_artifacts ADD COLUMN is_sensitive INTEGER NOT NULL DEFAULT 0');
|
|
294
|
+
}
|
|
295
|
+
db.prepare('INSERT OR IGNORE INTO schema_version (version, applied_at) VALUES (?, ?)')
|
|
296
|
+
.run(10, nowIso());
|
|
297
|
+
}
|
|
253
298
|
}
|
|
254
299
|
export { LATEST_SCHEMA_VERSION as SCHEMA_VERSION };
|
|
255
300
|
//# sourceMappingURL=schema.js.map
|
package/dist/seed.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Usage:
|
|
8
8
|
* const seeder = new WorkspaceSeeder(hypermem);
|
|
9
|
-
* const result = await seeder.seedWorkspace('/path/to/workspace', { agentId: '
|
|
9
|
+
* const result = await seeder.seedWorkspace('/path/to/workspace', { agentId: 'alice' });
|
|
10
10
|
*
|
|
11
11
|
* Idempotent: skips files whose source hash hasn't changed since last index.
|
|
12
12
|
* Atomic: each file's chunks are swapped in a single transaction.
|
package/dist/seed.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Usage:
|
|
8
8
|
* const seeder = new WorkspaceSeeder(hypermem);
|
|
9
|
-
* const result = await seeder.seedWorkspace('/path/to/workspace', { agentId: '
|
|
9
|
+
* const result = await seeder.seedWorkspace('/path/to/workspace', { agentId: 'alice' });
|
|
10
10
|
*
|
|
11
11
|
* Idempotent: skips files whose source hash hasn't changed since last index.
|
|
12
12
|
* Atomic: each file's chunks are swapped in a single transaction.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* session-flusher.ts
|
|
3
3
|
*
|
|
4
|
-
* Provides a clean, operator-safe way to flush a session's hot cache
|
|
4
|
+
* Provides a clean, operator-safe way to flush a session's hot cache
|
|
5
5
|
* without touching long-term memory (facts, vectors, episodes, knowledge graph).
|
|
6
6
|
*
|
|
7
7
|
* Used to implement the /fresh slash command — lets users start a new unwarmed
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import type { CacheLayer } from './cache.js';
|
|
14
14
|
export interface FlushSessionOptions {
|
|
15
|
-
/** If true, also clears topic-level
|
|
15
|
+
/** If true, also clears topic-level hot-cache entries for this session */
|
|
16
16
|
includeTopics?: boolean;
|
|
17
17
|
}
|
|
18
18
|
export interface FlushSessionResult {
|
|
@@ -33,8 +33,8 @@ export interface FlushSessionResult {
|
|
|
33
33
|
* from those stores naturally.
|
|
34
34
|
*
|
|
35
35
|
* @param cache Connected CacheLayer instance
|
|
36
|
-
* @param agentId Agent identifier (e.g. "
|
|
37
|
-
* @param sessionKey Full session key (e.g. "agent:
|
|
36
|
+
* @param agentId Agent identifier (e.g. "alice")
|
|
37
|
+
* @param sessionKey Full session key (e.g. "agent:alice:webchat:scratchpad")
|
|
38
38
|
* @param opts Optional flags
|
|
39
39
|
*/
|
|
40
40
|
export declare function flushSession(cache: CacheLayer, agentId: string, sessionKey: string, opts?: FlushSessionOptions): Promise<FlushSessionResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-flusher.d.ts","sourceRoot":"","sources":["../src/session-flusher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,WAAW,mBAAmB;IAClC,
|
|
1
|
+
{"version":3,"file":"session-flusher.d.ts","sourceRoot":"","sources":["../src/session-flusher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,WAAW,mBAAmB;IAClC,0EAA0E;IAC1E,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,iCAAiC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,uBAAuB;IACvB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,IAAI,GAAE,mBAAwB,GAC7B,OAAO,CAAC,kBAAkB,CAAC,CA2B7B;AAED;;GAEG;AACH,qBAAa,cAAc;IAEvB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBADP,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,MAAM;IAGlC;;OAEG;IACG,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAGzF"}
|
package/dist/session-flusher.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* session-flusher.ts
|
|
3
3
|
*
|
|
4
|
-
* Provides a clean, operator-safe way to flush a session's hot cache
|
|
4
|
+
* Provides a clean, operator-safe way to flush a session's hot cache
|
|
5
5
|
* without touching long-term memory (facts, vectors, episodes, knowledge graph).
|
|
6
6
|
*
|
|
7
7
|
* Used to implement the /fresh slash command — lets users start a new unwarmed
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
* from those stores naturally.
|
|
19
19
|
*
|
|
20
20
|
* @param cache Connected CacheLayer instance
|
|
21
|
-
* @param agentId Agent identifier (e.g. "
|
|
22
|
-
* @param sessionKey Full session key (e.g. "agent:
|
|
21
|
+
* @param agentId Agent identifier (e.g. "alice")
|
|
22
|
+
* @param sessionKey Full session key (e.g. "agent:alice:webchat:scratchpad")
|
|
23
23
|
* @param opts Optional flags
|
|
24
24
|
*/
|
|
25
25
|
export async function flushSession(cache, agentId, sessionKey, opts = {}) {
|
package/dist/spawn-context.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Usage:
|
|
8
8
|
* const ctx = await buildSpawnContext(messageStore, docChunkStore, agentId, {
|
|
9
|
-
* parentSessionKey: 'agent:
|
|
9
|
+
* parentSessionKey: 'agent:alice:webchat:main',
|
|
10
10
|
* workingSnapshot: 10,
|
|
11
11
|
* documents: ['/path/to/spec.md'],
|
|
12
12
|
* });
|
package/dist/spawn-context.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Usage:
|
|
8
8
|
* const ctx = await buildSpawnContext(messageStore, docChunkStore, agentId, {
|
|
9
|
-
* parentSessionKey: 'agent:
|
|
9
|
+
* parentSessionKey: 'agent:alice:webchat:main',
|
|
10
10
|
* workingSnapshot: 10,
|
|
11
11
|
* documents: ['/path/to/spec.md'],
|
|
12
12
|
* });
|
package/dist/temporal-store.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"temporal-store.d.ts","sourceRoot":"","sources":["../src/temporal-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qDAAqD;IACrD,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IACvB,gCAAgC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAeD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAGzD;AAED,qBAAa,aAAa;IACZ,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,YAAY;IAE7C;;;;OAIG;IACH,SAAS,CACP,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,
|
|
1
|
+
{"version":3,"file":"temporal-store.d.ts","sourceRoot":"","sources":["../src/temporal-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qDAAqD;IACrD,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IACvB,gCAAgC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAeD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAGzD;AAED,qBAAa,aAAa;IACZ,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,YAAY;IAE7C;;;;OAIG;IACH,SAAS,CACP,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GACxF,IAAI;IAkBP;;;OAGG;IACH,cAAc,CAAC,IAAI,GAAE,oBAAyB,GAAG,YAAY,EAAE;IAgE/D;;;OAGG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,YAAY,EAAE;IAIvD;;OAEG;IACH,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAOxC;;;OAGG;IACH,QAAQ,IAAI,MAAM;CAenB"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Artifact Store
|
|
3
|
+
*
|
|
4
|
+
* Durable, addressable storage for full tool result payloads. Schema v9.
|
|
5
|
+
*
|
|
6
|
+
* Why: the wave-guard at ingest time replaces oversized tool result payloads
|
|
7
|
+
* with a small stub for pressure relief. Before this store existed, the full
|
|
8
|
+
* payload was discarded. Now the stub in the transcript carries an
|
|
9
|
+
* `artifactId` pointing at the durable copy here, and hydration is an
|
|
10
|
+
* explicit decision, not an automatic transcript rewrite.
|
|
11
|
+
*
|
|
12
|
+
* Retention is deliberately independent of transcript eviction. Artifacts
|
|
13
|
+
* outlive the messages that referenced them, and GC is a separate concern
|
|
14
|
+
* (Phase 2).
|
|
15
|
+
*
|
|
16
|
+
* See: specs/TOOL_ARTIFACT_STORE.md
|
|
17
|
+
*/
|
|
18
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
19
|
+
export interface ToolArtifactRetentionPolicy {
|
|
20
|
+
/** TTL in ms for non-sensitive artifacts (e.g. 7 * 24 * 60 * 60 * 1000). */
|
|
21
|
+
standardTtlMs: number;
|
|
22
|
+
/** TTL in ms for sensitive artifacts. Should be <= standardTtlMs. */
|
|
23
|
+
sensitiveTtlMs: number;
|
|
24
|
+
/** Optional: max artifacts to keep per (agent_id, session_key). Excess removed oldest-first. */
|
|
25
|
+
maxPerSession?: number;
|
|
26
|
+
}
|
|
27
|
+
export interface ToolArtifactRecord {
|
|
28
|
+
id: string;
|
|
29
|
+
contentHash: string;
|
|
30
|
+
agentId: string;
|
|
31
|
+
sessionKey: string;
|
|
32
|
+
conversationId: number | null;
|
|
33
|
+
messageId: number | null;
|
|
34
|
+
turnId: string | null;
|
|
35
|
+
toolCallId: string | null;
|
|
36
|
+
toolName: string;
|
|
37
|
+
isError: boolean;
|
|
38
|
+
contentType: string;
|
|
39
|
+
sizeBytes: number;
|
|
40
|
+
tokenEstimate: number;
|
|
41
|
+
payload: string;
|
|
42
|
+
summary: string | null;
|
|
43
|
+
createdAt: string;
|
|
44
|
+
lastUsedAt: string;
|
|
45
|
+
refCount: number;
|
|
46
|
+
isSensitive: boolean;
|
|
47
|
+
}
|
|
48
|
+
export interface PutToolArtifactInput {
|
|
49
|
+
agentId: string;
|
|
50
|
+
sessionKey: string;
|
|
51
|
+
conversationId?: number;
|
|
52
|
+
messageId?: number;
|
|
53
|
+
turnId?: string;
|
|
54
|
+
toolCallId?: string;
|
|
55
|
+
toolName: string;
|
|
56
|
+
isError?: boolean;
|
|
57
|
+
contentType?: string;
|
|
58
|
+
payload: string;
|
|
59
|
+
summary?: string;
|
|
60
|
+
isSensitive?: boolean;
|
|
61
|
+
}
|
|
62
|
+
export declare class ToolArtifactStore {
|
|
63
|
+
private readonly db;
|
|
64
|
+
constructor(db: DatabaseSync);
|
|
65
|
+
/**
|
|
66
|
+
* Insert a new artifact, or dedupe against an existing one in the same
|
|
67
|
+
* (agentId, sessionKey) scope. Dedupe is scoped to a session so distinct
|
|
68
|
+
* sessions can't leak artifact ids across each other even when payload
|
|
69
|
+
* content is identical.
|
|
70
|
+
*/
|
|
71
|
+
put(input: PutToolArtifactInput): ToolArtifactRecord;
|
|
72
|
+
/** Alias for get(id) — explicit name used by the compositor hydration pass. */
|
|
73
|
+
getById(id: string): ToolArtifactRecord | null;
|
|
74
|
+
get(id: string): ToolArtifactRecord | null;
|
|
75
|
+
getByHash(agentId: string, sessionKey: string, contentHash: string): ToolArtifactRecord | null;
|
|
76
|
+
listByTurn(sessionKey: string, turnId: string): ToolArtifactRecord[];
|
|
77
|
+
listByToolCall(toolCallId: string): ToolArtifactRecord[];
|
|
78
|
+
listRecent(agentId: string, sessionKey: string, limit?: number): ToolArtifactRecord[];
|
|
79
|
+
/** Update last_used_at — call this when hydration actually surfaces the payload. */
|
|
80
|
+
touch(id: string): void;
|
|
81
|
+
/**
|
|
82
|
+
* GC sweep: delete artifacts that exceed their TTL or per-session count cap.
|
|
83
|
+
* Returns total rows deleted.
|
|
84
|
+
*
|
|
85
|
+
* Sensitive artifacts use sensitiveTtlMs (shorter); standard artifacts use
|
|
86
|
+
* standardTtlMs. Optional maxPerSession bounds row count per (agent, session)
|
|
87
|
+
* using a ROW_NUMBER() window query — oldest last_used_at removed first.
|
|
88
|
+
*/
|
|
89
|
+
sweep(policy: ToolArtifactRetentionPolicy): number;
|
|
90
|
+
/**
|
|
91
|
+
* Delete artifacts whose last_used_at is older than the ISO cutoff.
|
|
92
|
+
* Returns the number of rows deleted. Phase 1: manual invocation only.
|
|
93
|
+
*/
|
|
94
|
+
deleteOlderThan(isoCutoff: string): number;
|
|
95
|
+
/** Debug / ops: row count across a session. */
|
|
96
|
+
count(agentId?: string, sessionKey?: string): number;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=tool-artifact-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-artifact-store.d.ts","sourceRoot":"","sources":["../src/tool-artifact-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AA0BhD,MAAM,WAAW,2BAA2B;IAC1C,4EAA4E;IAC5E,aAAa,EAAE,MAAM,CAAC;IACtB,qEAAqE;IACrE,cAAc,EAAE,MAAM,CAAC;IACvB,gGAAgG;IAChG,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AA0BD,qBAAa,iBAAiB;IAChB,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,YAAY;IAE7C;;;;;OAKG;IACH,GAAG,CAAC,KAAK,EAAE,oBAAoB,GAAG,kBAAkB;IA+FpD,+EAA+E;IAC/E,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI;IAI9C,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI;IAO1C,SAAS,CACP,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAClB,kBAAkB,GAAG,IAAI;IAY5B,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,kBAAkB,EAAE;IAWpE,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,kBAAkB,EAAE;IAWxD,UAAU,CACR,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,KAAK,GAAE,MAAW,GACjB,kBAAkB,EAAE;IAYvB,oFAAoF;IACpF,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAMvB;;;;;;;OAOG;IACH,KAAK,CAAC,MAAM,EAAE,2BAA2B,GAAG,MAAM;IAsClD;;;OAGG;IACH,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAO1C,+CAA+C;IAC/C,KAAK,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM;CAcrD"}
|