@psiclawops/hypermem 0.5.6 → 0.7.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.
Files changed (67) hide show
  1. package/README.md +11 -54
  2. package/dist/background-indexer.d.ts.map +1 -1
  3. package/dist/background-indexer.js +26 -18
  4. package/dist/cache.d.ts.map +1 -1
  5. package/dist/cache.js +16 -2
  6. package/dist/compositor.d.ts.map +1 -1
  7. package/dist/compositor.js +146 -19
  8. package/dist/context-backfill.d.ts +46 -0
  9. package/dist/context-backfill.d.ts.map +1 -0
  10. package/dist/context-backfill.js +113 -0
  11. package/dist/context-store.d.ts +77 -0
  12. package/dist/context-store.d.ts.map +1 -0
  13. package/dist/context-store.js +177 -0
  14. package/dist/contradiction-detector.d.ts +78 -0
  15. package/dist/contradiction-detector.d.ts.map +1 -0
  16. package/dist/contradiction-detector.js +362 -0
  17. package/dist/cross-agent.d.ts +12 -0
  18. package/dist/cross-agent.d.ts.map +1 -1
  19. package/dist/cross-agent.js +31 -19
  20. package/dist/db.d.ts.map +1 -1
  21. package/dist/db.js +8 -0
  22. package/dist/dreaming-promoter.d.ts +1 -1
  23. package/dist/dreaming-promoter.js +1 -1
  24. package/dist/expertise-store.d.ts +129 -0
  25. package/dist/expertise-store.d.ts.map +1 -0
  26. package/dist/expertise-store.js +342 -0
  27. package/dist/fact-store.d.ts +15 -0
  28. package/dist/fact-store.d.ts.map +1 -1
  29. package/dist/fact-store.js +52 -5
  30. package/dist/index.d.ts +9 -3
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +27 -6
  33. package/dist/library-schema.d.ts +1 -1
  34. package/dist/library-schema.d.ts.map +1 -1
  35. package/dist/library-schema.js +72 -2
  36. package/dist/message-store.d.ts +31 -2
  37. package/dist/message-store.d.ts.map +1 -1
  38. package/dist/message-store.js +131 -17
  39. package/dist/preference-store.d.ts +1 -1
  40. package/dist/preference-store.js +1 -1
  41. package/dist/profiles.d.ts +3 -1
  42. package/dist/profiles.d.ts.map +1 -1
  43. package/dist/profiles.js +8 -0
  44. package/dist/repair-tool-pairs.d.ts.map +1 -1
  45. package/dist/repair-tool-pairs.js +73 -2
  46. package/dist/schema.d.ts +1 -1
  47. package/dist/schema.d.ts.map +1 -1
  48. package/dist/schema.js +27 -1
  49. package/dist/seed.d.ts +1 -1
  50. package/dist/seed.js +1 -1
  51. package/dist/session-flusher.d.ts +2 -2
  52. package/dist/session-flusher.js +2 -2
  53. package/dist/spawn-context.d.ts +1 -1
  54. package/dist/spawn-context.js +1 -1
  55. package/dist/temporal-store.d.ts +1 -0
  56. package/dist/temporal-store.d.ts.map +1 -1
  57. package/dist/topic-synthesizer.js +1 -1
  58. package/dist/trigger-registry.d.ts +1 -1
  59. package/dist/trigger-registry.js +4 -4
  60. package/dist/types.d.ts +15 -3
  61. package/dist/types.d.ts.map +1 -1
  62. package/dist/vector-store.d.ts +10 -1
  63. package/dist/vector-store.d.ts.map +1 -1
  64. package/dist/vector-store.js +353 -0
  65. package/dist/version.d.ts +5 -5
  66. package/dist/version.js +5 -5
  67. package/package.json +3 -2
@@ -0,0 +1,362 @@
1
+ /**
2
+ * Contradiction Detector — heuristic-based contradiction detection for the fact store.
3
+ *
4
+ * Detects when a newly ingested fact contradicts existing active facts using
5
+ * vector similarity (when available) and FTS candidate retrieval, scored by
6
+ * pattern-based heuristics (negation, numeric conflict, state conflict, temporal).
7
+ *
8
+ * No LLM calls — v1 is purely heuristic. LLM-enhanced scoring is a future item.
9
+ */
10
+ // ─── Internal Constants ──────────────────────────────────────────
11
+ const DEFAULT_CONFIG = {
12
+ minSimilarity: 0.6,
13
+ autoResolveThreshold: 0.85,
14
+ maxCandidates: 10,
15
+ autoResolve: true,
16
+ };
17
+ /** Words whose presence/absence flips meaning. */
18
+ const NEGATION_WORDS = new Set([
19
+ 'not', 'no', 'never', 'none', 'neither', 'nor', 'cannot', "can't",
20
+ "don't", "doesn't", "didn't", "won't", "wouldn't", "shouldn't",
21
+ "isn't", "aren't", "wasn't", "weren't", "hasn't", "haven't", "hadn't",
22
+ ]);
23
+ /** Antonym pairs where one in text A and the other in text B signals conflict. */
24
+ const STATE_ANTONYMS = [
25
+ ['enabled', 'disabled'],
26
+ ['active', 'inactive'],
27
+ ['active', 'deprecated'],
28
+ ['running', 'stopped'],
29
+ ['running', 'crashed'],
30
+ ['up', 'down'],
31
+ ['true', 'false'],
32
+ ['yes', 'no'],
33
+ ['on', 'off'],
34
+ ['open', 'closed'],
35
+ ['allowed', 'denied'],
36
+ ['allowed', 'blocked'],
37
+ ['available', 'unavailable'],
38
+ ['connected', 'disconnected'],
39
+ ['online', 'offline'],
40
+ ['present', 'absent'],
41
+ ['healthy', 'unhealthy'],
42
+ ['valid', 'invalid'],
43
+ ['complete', 'incomplete'],
44
+ ['success', 'failure'],
45
+ ];
46
+ // ─── Helpers ─────────────────────────────────────────────────────
47
+ /** Normalize text for comparison: lowercase, collapse whitespace. */
48
+ function normalize(text) {
49
+ return text.toLowerCase().replace(/\s+/g, ' ').trim();
50
+ }
51
+ /** Tokenize into word-boundary tokens. */
52
+ function tokenize(text) {
53
+ return normalize(text).split(/[\s,;:()[\]{}]+/).filter(Boolean);
54
+ }
55
+ /** Convert VectorStore distance (lower = closer) to a 0-1 similarity score. */
56
+ function distanceToSimilarity(distance) {
57
+ // sqlite-vec uses L2 distance by default. Convert to 0-1 similarity.
58
+ // distance=0 => similarity=1, distance grows => similarity decays toward 0.
59
+ return 1 / (1 + distance);
60
+ }
61
+ /**
62
+ * Build a safe FTS query from content. Takes the first several meaningful words
63
+ * to avoid FTS syntax errors from special characters.
64
+ */
65
+ function buildFtsQuery(content) {
66
+ const words = tokenize(content)
67
+ .filter(w => w.length > 2 && !/^\d+$/.test(w))
68
+ .slice(0, 6);
69
+ if (words.length === 0)
70
+ return '';
71
+ // OR-join for broad recall
72
+ return words.join(' OR ');
73
+ }
74
+ /**
75
+ * Extract numbers and their rough context (preceding word) from text.
76
+ * Returns pairs of [contextWord, number].
77
+ */
78
+ function extractNumbers(text) {
79
+ const results = [];
80
+ const tokens = tokenize(text);
81
+ for (let i = 0; i < tokens.length; i++) {
82
+ const num = parseFloat(tokens[i]);
83
+ if (!isNaN(num) && isFinite(num)) {
84
+ const context = i > 0 ? tokens[i - 1] : '';
85
+ results.push({ context, value: num });
86
+ }
87
+ }
88
+ return results;
89
+ }
90
+ /**
91
+ * Check if one text contains a negation of the other.
92
+ * Returns true if one has a negation word in a position where the other doesn't
93
+ * (or vice versa), given high token overlap.
94
+ */
95
+ function detectNegation(tokensA, tokensB) {
96
+ const negA = tokensA.filter(t => NEGATION_WORDS.has(t));
97
+ const negB = tokensB.filter(t => NEGATION_WORDS.has(t));
98
+ // One has negation words, the other doesn't (or different count)
99
+ if (negA.length !== negB.length) {
100
+ // Check that the non-negation content overlaps substantially
101
+ const contentA = new Set(tokensA.filter(t => !NEGATION_WORDS.has(t)));
102
+ const contentB = new Set(tokensB.filter(t => !NEGATION_WORDS.has(t)));
103
+ const intersection = [...contentA].filter(t => contentB.has(t));
104
+ const smaller = Math.min(contentA.size, contentB.size);
105
+ // Need at least 40% content overlap to consider it a negation of the same claim
106
+ return smaller > 0 && intersection.length / smaller >= 0.4;
107
+ }
108
+ return false;
109
+ }
110
+ /**
111
+ * Check for antonym state pairs between two token sets.
112
+ * Returns the matching antonym pair if found, or null.
113
+ */
114
+ function detectStateConflict(tokensA, tokensB) {
115
+ const setA = new Set(tokensA);
116
+ const setB = new Set(tokensB);
117
+ for (const [word1, word2] of STATE_ANTONYMS) {
118
+ if ((setA.has(word1) && setB.has(word2)) || (setA.has(word2) && setB.has(word1))) {
119
+ // Verify there's enough shared context (not just random words)
120
+ const contentA = new Set(tokensA.filter(t => t !== word1 && t !== word2));
121
+ const contentB = new Set(tokensB.filter(t => t !== word1 && t !== word2));
122
+ const intersection = [...contentA].filter(t => contentB.has(t));
123
+ const smaller = Math.min(contentA.size, contentB.size);
124
+ if (smaller > 0 && intersection.length / smaller >= 0.3) {
125
+ return setA.has(word1) ? [word1, word2] : [word2, word1];
126
+ }
127
+ }
128
+ }
129
+ return null;
130
+ }
131
+ /**
132
+ * Check for numeric conflicts: same contextual subject, different numbers.
133
+ */
134
+ function detectNumericConflict(textA, textB) {
135
+ const numsA = extractNumbers(textA);
136
+ const numsB = extractNumbers(textB);
137
+ for (const a of numsA) {
138
+ for (const b of numsB) {
139
+ // Same context word, different value
140
+ if (a.context && a.context === b.context && a.value !== b.value) {
141
+ return { contextWord: a.context, valueA: a.value, valueB: b.value };
142
+ }
143
+ }
144
+ }
145
+ return null;
146
+ }
147
+ // ─── ContradictionDetector ───────────────────────────────────────
148
+ export class ContradictionDetector {
149
+ factStore;
150
+ vectorStore;
151
+ config;
152
+ constructor(factStore, vectorStore, config) {
153
+ this.factStore = factStore;
154
+ this.vectorStore = vectorStore;
155
+ this.config = { ...DEFAULT_CONFIG, ...config };
156
+ }
157
+ /**
158
+ * On fact ingest, check if the new fact contradicts existing active facts.
159
+ * Uses vector similarity (when available) + FTS to find candidates, then
160
+ * scores each candidate with heuristic contradiction checks.
161
+ */
162
+ async detectOnIngest(agentId, newFact) {
163
+ const candidates = await this.findCandidates(agentId, newFact);
164
+ const contradictions = [];
165
+ for (const candidate of candidates) {
166
+ const scored = this.scoreContradiction(newFact.content, candidate);
167
+ if (scored) {
168
+ contradictions.push(scored);
169
+ }
170
+ }
171
+ // Sort by contradiction score descending
172
+ contradictions.sort((a, b) => b.contradictionScore - a.contradictionScore);
173
+ const result = {
174
+ contradictions,
175
+ autoResolved: false,
176
+ resolvedCount: 0,
177
+ };
178
+ return result;
179
+ }
180
+ /**
181
+ * Resolve a detected contradiction between an existing fact and a new fact.
182
+ */
183
+ resolveContradiction(oldFactId, newFactId, resolution) {
184
+ switch (resolution) {
185
+ case 'supersede':
186
+ this.factStore.markSuperseded(oldFactId, newFactId);
187
+ break;
188
+ case 'keep-both':
189
+ // No-op: both facts remain active
190
+ break;
191
+ case 'reject-new':
192
+ this.factStore.invalidateFact(newFactId);
193
+ break;
194
+ }
195
+ }
196
+ /**
197
+ * Auto-resolve high-confidence contradictions: newer supersedes older.
198
+ * Only resolves candidates above the autoResolveThreshold.
199
+ *
200
+ * @param agentId - The agent whose facts are being resolved (for audit trail)
201
+ * @param candidates - Scored contradiction candidates from detectOnIngest
202
+ * @returns Count of auto-resolved contradictions
203
+ */
204
+ async autoResolve(_agentId, candidates) {
205
+ if (!this.config.autoResolve)
206
+ return 0;
207
+ let resolved = 0;
208
+ for (const candidate of candidates) {
209
+ if (candidate.contradictionScore >= this.config.autoResolveThreshold) {
210
+ // The existing fact is older; the new fact (which triggered detection)
211
+ // is assumed to be the more recent truth. We mark the existing as superseded.
212
+ // Note: the caller must supply the newFactId when wiring this into ingest.
213
+ // For now, we invalidate the old fact since we don't have the new fact's id here.
214
+ this.factStore.invalidateFact(candidate.existingFactId);
215
+ resolved++;
216
+ }
217
+ }
218
+ return resolved;
219
+ }
220
+ // ─── Private Methods ────────────────────────────────────────────
221
+ /**
222
+ * Find candidate facts that might contradict the new fact.
223
+ * Uses vector search (if available) and FTS, deduplicates, and returns
224
+ * up to maxCandidates results above minSimilarity.
225
+ */
226
+ async findCandidates(agentId, newFact) {
227
+ const seen = new Set();
228
+ const candidates = [];
229
+ const { maxCandidates, minSimilarity } = this.config;
230
+ // Path 1: Vector similarity search (if VectorStore is available)
231
+ if (this.vectorStore) {
232
+ try {
233
+ const vectorResults = await this.vectorStore.search(newFact.content, {
234
+ tables: ['facts'],
235
+ limit: maxCandidates * 2, // over-fetch to allow for filtering
236
+ });
237
+ for (const vr of vectorResults) {
238
+ const similarity = distanceToSimilarity(vr.distance);
239
+ if (similarity < minSimilarity)
240
+ continue;
241
+ if (seen.has(vr.sourceId))
242
+ continue;
243
+ seen.add(vr.sourceId);
244
+ // Retrieve the full fact row for metadata checks
245
+ const facts = this.factStore.searchFacts(vr.content.slice(0, 30), {
246
+ agentId,
247
+ limit: 1,
248
+ });
249
+ const fact = facts.find(f => f.id === vr.sourceId);
250
+ if (fact && !fact.supersededBy && !fact.invalidAt) {
251
+ candidates.push({ fact, similarity });
252
+ }
253
+ }
254
+ }
255
+ catch {
256
+ // Vector search failed (embedding model unavailable, etc.)
257
+ // Fall through to FTS-only path
258
+ }
259
+ }
260
+ // Path 2: FTS search (always available, fills gaps)
261
+ if (candidates.length < maxCandidates) {
262
+ const ftsQuery = buildFtsQuery(newFact.content);
263
+ if (ftsQuery) {
264
+ try {
265
+ const ftsResults = this.factStore.searchFacts(ftsQuery, {
266
+ agentId,
267
+ domain: newFact.domain,
268
+ limit: maxCandidates * 2,
269
+ });
270
+ for (const fact of ftsResults) {
271
+ if (seen.has(fact.id))
272
+ continue;
273
+ if (fact.supersededBy || fact.invalidAt)
274
+ continue;
275
+ seen.add(fact.id);
276
+ // Compute a rough token-overlap similarity for FTS results
277
+ const similarity = this.tokenOverlapSimilarity(newFact.content, fact.content);
278
+ if (similarity >= minSimilarity) {
279
+ candidates.push({ fact, similarity });
280
+ }
281
+ }
282
+ }
283
+ catch {
284
+ // FTS query failed (malformed query, etc.)
285
+ }
286
+ }
287
+ }
288
+ // Sort by similarity descending, trim to maxCandidates
289
+ candidates.sort((a, b) => b.similarity - a.similarity);
290
+ return candidates.slice(0, maxCandidates);
291
+ }
292
+ /**
293
+ * Score a candidate fact against the new fact content for contradiction.
294
+ * Returns a ContradictionCandidate if any heuristic fires, null otherwise.
295
+ */
296
+ scoreContradiction(newContent, candidate) {
297
+ const existingContent = candidate.fact.content;
298
+ const tokensNew = tokenize(newContent);
299
+ const tokensExisting = tokenize(existingContent);
300
+ let bestScore = 0;
301
+ let bestReason = '';
302
+ // Heuristic 1: Negation detection (score: 0.9)
303
+ if (detectNegation(tokensNew, tokensExisting)) {
304
+ bestScore = 0.9;
305
+ bestReason = 'Negation detected: one fact negates the other';
306
+ }
307
+ // Heuristic 2: State conflict via antonym pairs (score: 0.85)
308
+ const stateConflict = detectStateConflict(tokensNew, tokensExisting);
309
+ if (stateConflict && stateConflict.length === 2) {
310
+ const score = 0.85;
311
+ if (score > bestScore) {
312
+ bestScore = score;
313
+ bestReason = `State conflict: "${stateConflict[0]}" vs "${stateConflict[1]}"`;
314
+ }
315
+ }
316
+ // Heuristic 3: Numeric conflict (score: 0.8)
317
+ const numConflict = detectNumericConflict(newContent, existingContent);
318
+ if (numConflict) {
319
+ const score = 0.8;
320
+ if (score > bestScore) {
321
+ bestScore = score;
322
+ bestReason = `Numeric conflict on "${numConflict.contextWord}": ${numConflict.valueA} vs ${numConflict.valueB}`;
323
+ }
324
+ }
325
+ // Heuristic 4: Temporal supersede — high similarity, different conclusion (score: 0.7)
326
+ // If similarity is very high (>0.8) but content isn't identical, it's likely a revised version
327
+ if (bestScore === 0 && candidate.similarity > 0.8) {
328
+ const contentDiffers = normalize(newContent) !== normalize(existingContent);
329
+ if (contentDiffers) {
330
+ bestScore = 0.7;
331
+ bestReason = 'Temporal supersede: high similarity with different content (likely revised)';
332
+ }
333
+ }
334
+ if (bestScore === 0)
335
+ return null;
336
+ return {
337
+ existingFactId: candidate.fact.id,
338
+ existingContent,
339
+ similarityScore: candidate.similarity,
340
+ contradictionScore: bestScore,
341
+ reason: bestReason,
342
+ };
343
+ }
344
+ /**
345
+ * Compute Jaccard-like token overlap between two texts.
346
+ * Returns 0-1 where 1 means identical token sets.
347
+ */
348
+ tokenOverlapSimilarity(textA, textB) {
349
+ const setA = new Set(tokenize(textA));
350
+ const setB = new Set(tokenize(textB));
351
+ if (setA.size === 0 || setB.size === 0)
352
+ return 0;
353
+ let intersection = 0;
354
+ for (const token of setA) {
355
+ if (setB.has(token))
356
+ intersection++;
357
+ }
358
+ const union = new Set([...setA, ...setB]).size;
359
+ return union > 0 ? intersection / union : 0;
360
+ }
361
+ }
362
+ //# sourceMappingURL=contradiction-detector.js.map
@@ -25,6 +25,18 @@ export interface OrgRegistry {
25
25
  }
26
26
  /**
27
27
  * Default fleet org structure.
28
+ *
29
+ * ── EXAMPLE DATA ──────────────────────────────────────────────────────────
30
+ * The agent names below (agent1, agent2, director1, etc.) are PLACEHOLDERS.
31
+ * Replace them with your own agent IDs to match your fleet configuration.
32
+ *
33
+ * Single-agent installs: you don't need to edit this. Your agent ID is
34
+ * resolved automatically at runtime from your OpenClaw config.
35
+ *
36
+ * Multi-agent installs: edit the agents map and orgs map below, then
37
+ * rebuild (`npm run build`). See INSTALL.md § "Configure your fleet" for
38
+ * a worked example.
39
+ * ─────────────────────────────────────────────────────────────────────────
28
40
  */
29
41
  export declare function defaultOrgRegistry(): OrgRegistry;
30
42
  export declare function canAccess(requester: AgentIdentity, target: AgentIdentity, visibility: MemoryVisibility, registry: OrgRegistry): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"cross-agent.d.ts","sourceRoot":"","sources":["../src/cross-agent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EACf,aAAa,EACd,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAK1C,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CACvC;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,WAAW,CA2BhD;AAID,wBAAgB,SAAS,CACvB,SAAS,EAAE,aAAa,EACxB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,gBAAgB,EAC5B,QAAQ,EAAE,WAAW,GACpB,OAAO,CAaT;AASD,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,aAAa,EACxB,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,WAAW,GACpB;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,OAAO,CAAC;IAAC,cAAc,EAAE,OAAO,CAAA;CAAE,CA6B3F;AAID;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,YAAY,GAAG,WAAW,CAgD3E;AAED;;;GAGG;AACH,eAAO,MAAM,qBAAqB,+BAAyB,CAAC;AAI5D;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,eAAe,EAC1B,KAAK,EAAE,eAAe,EACtB,QAAQ,EAAE,WAAW,GACpB,OAAO,EAAE,CAgCX"}
1
+ {"version":3,"file":"cross-agent.d.ts","sourceRoot":"","sources":["../src/cross-agent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EACf,aAAa,EACd,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAK1C,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CACvC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,IAAI,WAAW,CA2BhD;AAID,wBAAgB,SAAS,CACvB,SAAS,EAAE,aAAa,EACxB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,gBAAgB,EAC5B,QAAQ,EAAE,WAAW,GACpB,OAAO,CAaT;AASD,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,aAAa,EACxB,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,WAAW,GACpB;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,OAAO,CAAC;IAAC,cAAc,EAAE,OAAO,CAAA;CAAE,CA6B3F;AAID;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,YAAY,GAAG,WAAW,CAgD3E;AAED;;;GAGG;AACH,eAAO,MAAM,qBAAqB,+BAAyB,CAAC;AAI5D;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,eAAe,EAC1B,KAAK,EAAE,eAAe,EACtB,QAAQ,EAAE,WAAW,GACpB,OAAO,EAAE,CAgCX"}
@@ -19,30 +19,42 @@
19
19
  import { FleetStore } from './fleet-store.js';
20
20
  /**
21
21
  * Default fleet org structure.
22
+ *
23
+ * ── EXAMPLE DATA ──────────────────────────────────────────────────────────
24
+ * The agent names below (agent1, agent2, director1, etc.) are PLACEHOLDERS.
25
+ * Replace them with your own agent IDs to match your fleet configuration.
26
+ *
27
+ * Single-agent installs: you don't need to edit this. Your agent ID is
28
+ * resolved automatically at runtime from your OpenClaw config.
29
+ *
30
+ * Multi-agent installs: edit the agents map and orgs map below, then
31
+ * rebuild (`npm run build`). See INSTALL.md § "Configure your fleet" for
32
+ * a worked example.
33
+ * ─────────────────────────────────────────────────────────────────────────
22
34
  */
23
35
  export function defaultOrgRegistry() {
24
36
  const agents = {
25
- alice: { agentId: 'alice', tier: 'council' },
26
- bob: { agentId: 'bob', tier: 'council' },
27
- clarity: { agentId: 'clarity', tier: 'council' },
28
- dave: { agentId: 'dave', tier: 'council' },
29
- carol: { agentId: 'carol', tier: 'council' },
30
- oscar: { agentId: 'oscar', tier: 'council' },
31
- hank: { agentId: 'hank', tier: 'director', org: 'alice-org', councilLead: 'alice' },
32
- jack: { agentId: 'jack', tier: 'director', org: 'alice-org', councilLead: 'alice' },
33
- irene: { agentId: 'irene', tier: 'director', org: 'alice-org', councilLead: 'alice' },
34
- eve: { agentId: 'eve', tier: 'director', org: 'bob-org', councilLead: 'bob' },
35
- frank: { agentId: 'frank', tier: 'director', org: 'bob-org', councilLead: 'bob' },
36
- grace: { agentId: 'grace', tier: 'director', org: 'bob-org', councilLead: 'bob' },
37
- leo: { agentId: 'leo', tier: 'director', org: 'dave-org', councilLead: 'dave' },
38
- kate: { agentId: 'kate', tier: 'director', org: 'dave-org', councilLead: 'dave' },
39
- mike: { agentId: 'mike', tier: 'specialist' },
40
- nancy: { agentId: 'nancy', tier: 'specialist' },
37
+ agent1: { agentId: 'agent1', tier: 'council' },
38
+ agent2: { agentId: 'agent2', tier: 'council' },
39
+ agent4: { agentId: 'agent4', tier: 'council' },
40
+ agent3: { agentId: 'agent3', tier: 'council' },
41
+ agent6: { agentId: 'agent6', tier: 'council' },
42
+ agent5: { agentId: 'agent5', tier: 'council' },
43
+ director1: { agentId: 'director1', tier: 'director', org: 'agent1-org', councilLead: 'agent1' },
44
+ director2: { agentId: 'director2', tier: 'director', org: 'agent1-org', councilLead: 'agent1' },
45
+ director3: { agentId: 'director3', tier: 'director', org: 'agent1-org', councilLead: 'agent1' },
46
+ director4: { agentId: 'director4', tier: 'director', org: 'agent2-org', councilLead: 'agent2' },
47
+ director5: { agentId: 'director5', tier: 'director', org: 'agent2-org', councilLead: 'agent2' },
48
+ director6: { agentId: 'director6', tier: 'director', org: 'agent2-org', councilLead: 'agent2' },
49
+ director7: { agentId: 'director7', tier: 'director', org: 'agent3-org', councilLead: 'agent3' },
50
+ director8: { agentId: 'director8', tier: 'director', org: 'agent3-org', councilLead: 'agent3' },
51
+ specialist1: { agentId: 'specialist1', tier: 'specialist' },
52
+ specialist2: { agentId: 'specialist2', tier: 'specialist' },
41
53
  };
42
54
  const orgs = {
43
- 'alice-org': ['alice', 'hank', 'jack', 'irene'],
44
- 'bob-org': ['bob', 'eve', 'frank', 'grace'],
45
- 'dave-org': ['dave', 'leo', 'kate'],
55
+ 'agent1-org': ['agent1', 'director1', 'director2', 'director3'],
56
+ 'agent2-org': ['agent2', 'director4', 'director5', 'director6'],
57
+ 'agent3-org': ['agent3', 'director7', 'director8'],
46
58
  };
47
59
  return { orgs, agents };
48
60
  }
package/dist/db.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAqC3C,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;CACjB;AAQD;;;GAGG;AACH,iBAAS,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAI9C;AAED;;;GAGG;AACH,iBAAS,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAIvD;AAmBD,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,CAAC;AAEpD,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAmC;IAC9D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmC;IAC7D,OAAO,CAAC,SAAS,CAA6B;IAC9C,OAAO,CAAC,aAAa,CAAwB;IAE7C,6EAA6E;IAC7E,IAAI,YAAY,IAAI,OAAO,CAE1B;gBAEW,MAAM,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC;IAKnD;;;OAGG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY;IAiB3C;;;;OAIG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IA0BjD;;;;;;OAMG;IACH,iBAAiB,IAAI,YAAY,GAAG,IAAI;IAsBxC;;;OAGG;IACH,YAAY,IAAI,YAAY;IAa5B;;;OAGG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY;IAIzC;;OAEG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAClC,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,GAAG,IAAI;IA2BR;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA+BxB;;OAEG;IACH,UAAU,IAAI,MAAM,EAAE;IAWtB;;OAEG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAKpC;;OAEG;IACH,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IAQzC;;OAEG;IACH,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAWzC;;;;;;;;;;;;OAYG;IACH,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IA8C/C;;;;;;;OAOG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QACnC,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,GAAG;QAAE,MAAM,EAAE,MAAM,GAAG,KAAK,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IA4BzE;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY;IAc9D;;OAEG;IACH,KAAK,IAAI,IAAI;CAgBd"}
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAuC3C,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;CACjB;AAQD;;;GAGG;AACH,iBAAS,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAI9C;AAED;;;GAGG;AACH,iBAAS,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAIvD;AAmBD,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,CAAC;AAEpD,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAmC;IAC9D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmC;IAC7D,OAAO,CAAC,SAAS,CAA6B;IAC9C,OAAO,CAAC,aAAa,CAAwB;IAE7C,6EAA6E;IAC7E,IAAI,YAAY,IAAI,OAAO,CAE1B;gBAEW,MAAM,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC;IAKnD;;;OAGG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY;IAwB3C;;;;OAIG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IA0BjD;;;;;;OAMG;IACH,iBAAiB,IAAI,YAAY,GAAG,IAAI;IAsBxC;;;OAGG;IACH,YAAY,IAAI,YAAY;IAa5B;;;OAGG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY;IAIzC;;OAEG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAClC,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,GAAG,IAAI;IA2BR;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA+BxB;;OAEG;IACH,UAAU,IAAI,MAAM,EAAE;IAWtB;;OAEG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAKpC;;OAEG;IACH,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IAQzC;;OAEG;IACH,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAWzC;;;;;;;;;;;;OAYG;IACH,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IA8C/C;;;;;;;OAOG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QACnC,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,GAAG;QAAE,MAAM,EAAE,MAAM,GAAG,KAAK,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IA4BzE;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY;IAc9D;;OAEG;IACH,KAAK,IAAI,IAAI;CAgBd"}
package/dist/db.js CHANGED
@@ -15,6 +15,8 @@ import path from 'node:path';
15
15
  import { migrate } from './schema.js';
16
16
  import { migrateLibrary } from './library-schema.js';
17
17
  import { ENGINE_VERSION } from './version.js';
18
+ import { ensureContextSchema } from './context-store.js';
19
+ import { backfillContexts } from './context-backfill.js';
18
20
  // sqlite-vec extension loading — optional dependency
19
21
  import { createRequire } from 'node:module';
20
22
  let sqliteVecAvailable = null;
@@ -106,6 +108,12 @@ export class DatabaseManager {
106
108
  db = new DatabaseSync(dbPath);
107
109
  applyPragmas(db);
108
110
  migrate(db);
111
+ ensureContextSchema(db);
112
+ // Backfill contexts for existing conversations on first run after migration
113
+ const contextCount = db.prepare('SELECT COUNT(*) as cnt FROM contexts').get();
114
+ if (contextCount.cnt === 0) {
115
+ backfillContexts(db);
116
+ }
109
117
  this.messageDbs.set(agentId, db);
110
118
  return db;
111
119
  }
@@ -67,7 +67,7 @@ export interface DreamerResult {
67
67
  }
68
68
  /**
69
69
  * Resolve the workspace directory for an agent.
70
- * Council agents live at ~/.openclaw/workspace/{agentId}/
70
+ * Council agents live at ~/.openclaw/workspace-council/{agentId}/
71
71
  * Other agents at ~/.openclaw/workspace/{agentId}/
72
72
  */
73
73
  export declare function resolveAgentWorkspacePath(agentId: string): Promise<string | null>;
@@ -31,7 +31,7 @@ export const DEFAULT_DREAMER_CONFIG = {
31
31
  // ─── Workspace path resolution ───────────────────────────────────────────────
32
32
  /**
33
33
  * Resolve the workspace directory for an agent.
34
- * Council agents live at ~/.openclaw/workspace/{agentId}/
34
+ * Council agents live at ~/.openclaw/workspace-council/{agentId}/
35
35
  * Other agents at ~/.openclaw/workspace/{agentId}/
36
36
  */
37
37
  export async function resolveAgentWorkspacePath(agentId) {
@@ -0,0 +1,129 @@
1
+ /**
2
+ * hypermem Expertise Store
3
+ *
4
+ * Stores domain expertise patterns — learned behaviors that make the Nth run
5
+ * better than the 1st. Two-phase lifecycle:
6
+ * 1. Observations: raw learnings logged from conversations, pipelines, reviews
7
+ * 2. Patterns: graduated observations with N≥3 confirming instances
8
+ *
9
+ * Patterns are agent-scoped but domain-tagged, enabling cross-agent queries.
10
+ * Patterns have confidence, frequency tracking, and decay on counter-evidence.
11
+ */
12
+ import type { DatabaseSync } from 'node:sqlite';
13
+ export interface ExpertiseObservation {
14
+ id: number;
15
+ agentId: string;
16
+ domain: string;
17
+ context: string | null;
18
+ observationText: string;
19
+ sourceType: 'conversation' | 'pipeline' | 'review' | 'manual';
20
+ sourceRef: string | null;
21
+ createdAt: string;
22
+ }
23
+ export interface ExpertisePattern {
24
+ id: number;
25
+ agentId: string;
26
+ domain: string;
27
+ patternText: string;
28
+ confidence: number;
29
+ frequency: number;
30
+ firstSeen: string;
31
+ lastConfirmed: string;
32
+ invalidatedAt: string | null;
33
+ invalidationReason: string | null;
34
+ decayScore: number;
35
+ }
36
+ export interface ExpertiseEvidence {
37
+ observationId: number;
38
+ patternId: number;
39
+ relationship: 'confirms' | 'contradicts';
40
+ createdAt: string;
41
+ }
42
+ export declare class ExpertiseStore {
43
+ private readonly db;
44
+ private readonly graduationThreshold;
45
+ constructor(db: DatabaseSync, graduationThreshold?: number);
46
+ /**
47
+ * Record a raw observation from any source.
48
+ */
49
+ record(agentId: string, observationText: string, domain: string, opts?: {
50
+ context?: string;
51
+ sourceType?: ExpertiseObservation['sourceType'];
52
+ sourceRef?: string;
53
+ }): ExpertiseObservation;
54
+ /**
55
+ * Get observations for an agent, optionally filtered by domain.
56
+ */
57
+ getObservations(agentId: string, opts?: {
58
+ domain?: string;
59
+ limit?: number;
60
+ }): ExpertiseObservation[];
61
+ /**
62
+ * Retrieve active expertise patterns for current work context.
63
+ * Returns patterns sorted by confidence DESC, frequency DESC.
64
+ * Excludes invalidated patterns by default.
65
+ */
66
+ query(agentId: string, domain: string, opts?: {
67
+ context?: string;
68
+ includeInvalidated?: boolean;
69
+ limit?: number;
70
+ minConfidence?: number;
71
+ }): ExpertisePattern[];
72
+ /**
73
+ * Cross-agent query: get patterns from any agent in a given domain.
74
+ * Useful for fleet-wide expertise ("what has any agent learned about X?").
75
+ */
76
+ queryFleet(domain: string, opts?: {
77
+ limit?: number;
78
+ minConfidence?: number;
79
+ }): ExpertisePattern[];
80
+ /**
81
+ * Graduate an observation to a pattern.
82
+ *
83
+ * If a similar pattern already exists (same agent, domain, and pattern text prefix match),
84
+ * increments its frequency and updates lastConfirmed instead of creating a duplicate.
85
+ *
86
+ * Auto-graduation happens when an observation has N≥graduationThreshold confirming
87
+ * evidence links. Can also be called manually.
88
+ */
89
+ graduate(agentId: string, observationId: number, opts?: {
90
+ patternText?: string;
91
+ confidence?: number;
92
+ }): ExpertisePattern | null;
93
+ /**
94
+ * Record evidence linking an observation to a pattern.
95
+ * If this pushes a pattern's contradicting evidence past threshold,
96
+ * auto-invalidates the pattern.
97
+ */
98
+ addEvidence(observationId: number, patternId: number, relationship: 'confirms' | 'contradicts'): void;
99
+ /**
100
+ * Check if any observations are ready for auto-graduation.
101
+ * An observation graduates when it has N≥threshold confirming evidence links.
102
+ * Returns the number of newly graduated patterns.
103
+ */
104
+ autoGraduate(agentId: string): number;
105
+ /**
106
+ * Mark a pattern as invalidated.
107
+ */
108
+ invalidate(patternId: number, reason: string): boolean;
109
+ /**
110
+ * List all active patterns for an agent, optionally filtered by domain.
111
+ */
112
+ list(agentId: string, opts?: {
113
+ domain?: string;
114
+ includeInvalidated?: boolean;
115
+ }): ExpertisePattern[];
116
+ /**
117
+ * Decay all patterns by a fixed rate. Similar to fact decay.
118
+ */
119
+ decayPatterns(agentId: string, decayRate?: number): number;
120
+ /**
121
+ * Get pattern and observation counts for an agent.
122
+ */
123
+ getStats(agentId: string): {
124
+ observations: number;
125
+ activePatterns: number;
126
+ invalidatedPatterns: number;
127
+ };
128
+ }
129
+ //# sourceMappingURL=expertise-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expertise-store.d.ts","sourceRoot":"","sources":["../src/expertise-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIhD,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,cAAc,GAAG,UAAU,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC9D,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,UAAU,GAAG,aAAa,CAAC;IACzC,SAAS,EAAE,MAAM,CAAC;CACnB;AAsCD,qBAAa,cAAc;IAEvB,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,mBAAmB;gBADnB,EAAE,EAAE,YAAY,EAChB,mBAAmB,GAAE,MAAqC;IAK7E;;OAEG;IACH,MAAM,CACJ,OAAO,EAAE,MAAM,EACf,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE;QACL,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,UAAU,CAAC,EAAE,oBAAoB,CAAC,YAAY,CAAC,CAAC;QAChD,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,GACA,oBAAoB;IA8BvB;;OAEG;IACH,eAAe,CACb,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GACzC,oBAAoB,EAAE;IAsBzB;;;;OAIG;IACH,KAAK,CACH,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE;QACL,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,kBAAkB,CAAC,EAAE,OAAO,CAAC;QAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,GACA,gBAAgB,EAAE;IA4BrB;;;OAGG;IACH,UAAU,CACR,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,GAChD,gBAAgB,EAAE;IAyBrB;;;;;;;;OAQG;IACH,QAAQ,CACN,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,MAAM,EACrB,IAAI,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GACnD,gBAAgB,GAAG,IAAI;IA2E1B;;;;OAIG;IACH,WAAW,CACT,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,UAAU,GAAG,aAAa,GACvC,IAAI;IA0CP;;;;OAIG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAyBrC;;OAEG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO;IAUtD;;OAEG;IACH,IAAI,CACF,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,kBAAkB,CAAC,EAAE,OAAO,CAAA;KAAE,GACvD,gBAAgB,EAAE;IAmBrB;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,GAAE,MAAc,GAAG,MAAM;IASjE;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAC;QAAC,mBAAmB,EAAE,MAAM,CAAA;KAAE;CAgBzG"}