@psiclawops/hypermem 0.9.2 → 0.9.4
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/CHANGELOG.md +16 -0
- package/INSTALL.md +73 -70
- package/README.md +33 -51
- package/assets/default-config.json +47 -0
- package/bin/hypermem-doctor.mjs +76 -2
- package/bin/hypermem-status.mjs +255 -7
- package/dist/adaptive-lifecycle.d.ts +39 -0
- package/dist/adaptive-lifecycle.d.ts.map +1 -1
- package/dist/adaptive-lifecycle.js +87 -9
- package/dist/background-indexer.d.ts.map +1 -1
- package/dist/background-indexer.js +7 -5
- package/dist/compositor.d.ts.map +1 -1
- package/dist/compositor.js +239 -20
- package/dist/hybrid-retrieval.d.ts +8 -0
- package/dist/hybrid-retrieval.d.ts.map +1 -1
- package/dist/hybrid-retrieval.js +112 -10
- package/dist/index.d.ts +15 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -0
- package/dist/message-store.d.ts +62 -1
- package/dist/message-store.d.ts.map +1 -1
- package/dist/message-store.js +355 -2
- package/dist/open-domain.d.ts.map +1 -1
- package/dist/open-domain.js +3 -2
- package/dist/proactive-pass.d.ts +42 -2
- package/dist/proactive-pass.d.ts.map +1 -1
- package/dist/proactive-pass.js +294 -39
- package/dist/topic-synthesizer.d.ts.map +1 -1
- package/dist/topic-synthesizer.js +9 -3
- package/dist/types.d.ts +99 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/vector-store.d.ts +10 -1
- package/dist/vector-store.d.ts.map +1 -1
- package/dist/vector-store.js +45 -9
- package/docs/DIAGNOSTICS.md +87 -0
- package/docs/INTEGRATION_VALIDATION.md +40 -1
- package/docs/ROADMAP.md +25 -12
- package/docs/TUNING.md +45 -4
- package/install.sh +5 -60
- package/memory-plugin/dist/index.d.ts +24 -0
- package/memory-plugin/dist/index.js +570 -0
- package/memory-plugin/openclaw.plugin.json +199 -2
- package/memory-plugin/package.json +3 -3
- package/package.json +24 -10
- package/plugin/dist/index.d.ts +210 -0
- package/plugin/dist/index.d.ts.map +1 -0
- package/plugin/dist/index.js +3641 -0
- package/plugin/dist/index.js.map +1 -0
- package/plugin/openclaw.plugin.json +199 -2
- package/plugin/package.json +4 -4
- package/scripts/install-packed-runtime.mjs +99 -0
- package/scripts/install-runtime.mjs +164 -4
package/dist/compositor.js
CHANGED
|
@@ -27,7 +27,7 @@ import { KnowledgeStore } from './knowledge-store.js';
|
|
|
27
27
|
import { TemporalStore, hasTemporalSignals } from './temporal-store.js';
|
|
28
28
|
import { isOpenDomainQuery, searchOpenDomain } from './open-domain.js';
|
|
29
29
|
import { TRIM_BUDGET_POLICY, resolveTrimBudgets } from './budget-policy.js';
|
|
30
|
-
import { resolveAdaptiveLifecyclePolicy } from './adaptive-lifecycle.js';
|
|
30
|
+
import { resolveAdaptiveLifecyclePolicy, countTopicBearingTurns } from './adaptive-lifecycle.js';
|
|
31
31
|
import { formatToolChainStub, parseToolChainStub, formatArtifactRef, isArtifactRef } from './degradation.js';
|
|
32
32
|
import { ToolArtifactStore } from './tool-artifact-store.js';
|
|
33
33
|
import { insertCompositionSnapshot, getLatestValidCompositionSnapshot, listCompositionSnapshots, MAX_WARM_RESTORE_REPAIR_DEPTH, } from './composition-snapshot-store.js';
|
|
@@ -42,6 +42,8 @@ export const OPENCLAW_BOOTSTRAP_FILES = new Set([
|
|
|
42
42
|
'AGENTS.md', 'HEARTBEAT.md', 'MEMORY.md', 'BOOTSTRAP.md',
|
|
43
43
|
]);
|
|
44
44
|
const CACHE_PREFIX_BOUNDARY_SLOT = 'cache-prefix-boundary';
|
|
45
|
+
const LITERAL_ANTECEDENT_GUARD_MAX_MESSAGES = 3;
|
|
46
|
+
const LITERAL_ANTECEDENT_GUARD_MAX_TOKENS = 4_000;
|
|
45
47
|
/**
|
|
46
48
|
* Model context window sizes by provider/model string (or partial match).
|
|
47
49
|
* Used as fallback when tokenBudget is not passed by the runtime.
|
|
@@ -419,6 +421,33 @@ const TOOL_RECENT_OVERSIZE_CHAR_THRESHOLD = 40_000;
|
|
|
419
421
|
const TOOL_RECENT_OVERSIZE_TARGET_CHARS = 40_000;
|
|
420
422
|
const TOOL_RECENT_OVERSIZE_MAX_TAIL_CHARS = 12_000;
|
|
421
423
|
const TOOL_TRIM_NOTE_PREFIX = '[hypermem_tool_result_trim';
|
|
424
|
+
// 0.9.4 Packet 3: afterTurn protected warming floor.
|
|
425
|
+
// refreshRedisGradient only receives the resolved trim target, not the full
|
|
426
|
+
// lifecycle policy. Keep this private and infer the early-session bands from
|
|
427
|
+
// the canonical Packet 1 trim targets so no public API/export surface changes.
|
|
428
|
+
// The floor is intentionally disabled once the lifecycle reaches elevated or
|
|
429
|
+
// worse; pressure bands at/above elevated are allowed to reclaim warming.
|
|
430
|
+
const AFTERTURN_PROTECTED_WARMING_ELEVATED_FLOOR_FRACTION = 0.34;
|
|
431
|
+
const AFTERTURN_PROTECTED_WARMING_BOOTSTRAP_FLOOR_FRACTION = Math.max(AFTERTURN_PROTECTED_WARMING_ELEVATED_FLOOR_FRACTION, 0.62 * 0.60);
|
|
432
|
+
const AFTERTURN_PROTECTED_WARMING_WARMUP_FLOOR_FRACTION = Math.max(AFTERTURN_PROTECTED_WARMING_ELEVATED_FLOOR_FRACTION, 0.55 * 0.60);
|
|
433
|
+
const AFTERTURN_PROTECTED_WARMING_TRIM_EPSILON = 0.0001;
|
|
434
|
+
function resolveAfterTurnProtectedWarmingFloor(tokenBudget, trimSoftTarget) {
|
|
435
|
+
const safeBudget = Math.max(0, Math.floor(tokenBudget || 0));
|
|
436
|
+
if (safeBudget <= 0 || trimSoftTarget == null) {
|
|
437
|
+
return { floorFraction: 0, floorTokens: 0, band: null };
|
|
438
|
+
}
|
|
439
|
+
// Packet 1 trim targets: bootstrap=0.72, warmup=0.68. Steady=0.65 and
|
|
440
|
+
// elevated=0.60 do not get this protected floor.
|
|
441
|
+
if (Math.abs(trimSoftTarget - 0.72) <= AFTERTURN_PROTECTED_WARMING_TRIM_EPSILON) {
|
|
442
|
+
const floorFraction = AFTERTURN_PROTECTED_WARMING_BOOTSTRAP_FLOOR_FRACTION;
|
|
443
|
+
return { floorFraction, floorTokens: Math.floor(safeBudget * floorFraction), band: 'bootstrap' };
|
|
444
|
+
}
|
|
445
|
+
if (Math.abs(trimSoftTarget - 0.68) <= AFTERTURN_PROTECTED_WARMING_TRIM_EPSILON) {
|
|
446
|
+
const floorFraction = AFTERTURN_PROTECTED_WARMING_WARMUP_FLOOR_FRACTION;
|
|
447
|
+
return { floorFraction, floorTokens: Math.floor(safeBudget * floorFraction), band: 'warmup' };
|
|
448
|
+
}
|
|
449
|
+
return { floorFraction: 0, floorTokens: 0, band: null };
|
|
450
|
+
}
|
|
422
451
|
// ─── Trigger Registry ────────────────────────────────────────────
|
|
423
452
|
// Moved to src/trigger-registry.ts (W5).
|
|
424
453
|
// CollectionTrigger, DEFAULT_TRIGGERS, matchTriggers imported above.
|
|
@@ -465,6 +494,57 @@ function clusterNeutralMessages(messages) {
|
|
|
465
494
|
}
|
|
466
495
|
return clusters;
|
|
467
496
|
}
|
|
497
|
+
function resolveLiteralAntecedentGuardClusterIndices(clusters, opts) {
|
|
498
|
+
const protectedIndices = new Set();
|
|
499
|
+
const currentPrompt = opts.currentPrompt?.trim() ?? '';
|
|
500
|
+
if (!opts.enabled || clusters.length < (currentPrompt ? 1 : 2))
|
|
501
|
+
return protectedIndices;
|
|
502
|
+
let boundaryClusterIdx;
|
|
503
|
+
if (currentPrompt) {
|
|
504
|
+
for (let i = clusters.length - 1; i >= 0; i--) {
|
|
505
|
+
const containsCurrentPrompt = clusters[i].messages.some(msg => msg.role === 'user' && (msg.textContent ?? '').trim() === currentPrompt);
|
|
506
|
+
if (containsCurrentPrompt) {
|
|
507
|
+
boundaryClusterIdx = i;
|
|
508
|
+
break;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
// In the plugin compose path the current prompt is often request.prompt and
|
|
512
|
+
// is appended after compose, so it has no persisted cluster yet. Treat the
|
|
513
|
+
// end of persisted history as the prompt boundary in that case.
|
|
514
|
+
if (boundaryClusterIdx == null)
|
|
515
|
+
boundaryClusterIdx = clusters.length;
|
|
516
|
+
}
|
|
517
|
+
else {
|
|
518
|
+
const latestClusterIdx = clusters.length - 1;
|
|
519
|
+
const latestCluster = clusters[latestClusterIdx];
|
|
520
|
+
if (!latestCluster.messages.some(msg => msg.role === 'user'))
|
|
521
|
+
return protectedIndices;
|
|
522
|
+
boundaryClusterIdx = latestClusterIdx;
|
|
523
|
+
}
|
|
524
|
+
if (boundaryClusterIdx <= 0)
|
|
525
|
+
return protectedIndices;
|
|
526
|
+
const maxMessages = Math.max(0, Math.floor(opts.maxMessages ?? LITERAL_ANTECEDENT_GUARD_MAX_MESSAGES));
|
|
527
|
+
const maxTokens = Math.max(0, Math.floor(opts.maxTokens ?? LITERAL_ANTECEDENT_GUARD_MAX_TOKENS));
|
|
528
|
+
if (maxMessages <= 0 || maxTokens <= 0)
|
|
529
|
+
return protectedIndices;
|
|
530
|
+
let messageCount = 0;
|
|
531
|
+
let tokenCount = 0;
|
|
532
|
+
for (let i = boundaryClusterIdx - 1; i >= 0; i--) {
|
|
533
|
+
const cluster = clusters[i];
|
|
534
|
+
const nextMessageCount = messageCount + cluster.messages.length;
|
|
535
|
+
const nextTokenCount = tokenCount + cluster.tokenCost;
|
|
536
|
+
if (nextMessageCount > maxMessages)
|
|
537
|
+
break;
|
|
538
|
+
if (nextTokenCount > maxTokens)
|
|
539
|
+
break;
|
|
540
|
+
protectedIndices.add(i);
|
|
541
|
+
messageCount = nextMessageCount;
|
|
542
|
+
tokenCount = nextTokenCount;
|
|
543
|
+
if (messageCount >= maxMessages)
|
|
544
|
+
break;
|
|
545
|
+
}
|
|
546
|
+
return protectedIndices;
|
|
547
|
+
}
|
|
468
548
|
export function orderClustersForAdaptiveEviction(clusters, policy, opts = {}) {
|
|
469
549
|
const plan = policy.evictionPlan;
|
|
470
550
|
const protectedIndices = new Set();
|
|
@@ -1043,6 +1123,17 @@ export function resolveArtifactOversizeThreshold(effectiveBudget) {
|
|
|
1043
1123
|
function isExplicitNewSessionPrompt(prompt) {
|
|
1044
1124
|
return /^\/new(?:\s|$)/i.test((prompt ?? '').trim());
|
|
1045
1125
|
}
|
|
1126
|
+
function parsePersistedTopicBearingTurnCount(raw) {
|
|
1127
|
+
if (raw == null)
|
|
1128
|
+
return null;
|
|
1129
|
+
const trimmed = raw.trim();
|
|
1130
|
+
if (trimmed.length === 0)
|
|
1131
|
+
return null;
|
|
1132
|
+
const parsed = Number.parseInt(trimmed, 10);
|
|
1133
|
+
if (!Number.isFinite(parsed) || parsed < 0)
|
|
1134
|
+
return null;
|
|
1135
|
+
return Math.floor(parsed);
|
|
1136
|
+
}
|
|
1046
1137
|
/**
|
|
1047
1138
|
* C2: Degrade an oversized doc chunk to a canonical ArtifactRef string.
|
|
1048
1139
|
*
|
|
@@ -1625,6 +1716,14 @@ export class Compositor {
|
|
|
1625
1716
|
const s09SampleTokens = sampleMessages.reduce((sum, m) => sum + estimateMessageTokens(m), 0);
|
|
1626
1717
|
const s09EvictionPressure = computeUnifiedPressure(s09SampleTokens, budget, PRESSURE_SOURCE.COMPOSE_PRE_RECALL);
|
|
1627
1718
|
let s09ObservedUserTurnCount = sampleMessages.filter(m => m.role === 'user').length;
|
|
1719
|
+
let s09PersistedTopicBearingTurnCount = null;
|
|
1720
|
+
try {
|
|
1721
|
+
s09PersistedTopicBearingTurnCount = parsePersistedTopicBearingTurnCount(await this.cache.getSlot(request.agentId, request.sessionKey, 'topicBearingTurnCount'));
|
|
1722
|
+
}
|
|
1723
|
+
catch {
|
|
1724
|
+
s09PersistedTopicBearingTurnCount = null;
|
|
1725
|
+
}
|
|
1726
|
+
let s09TopicBearingTurnCount = s09PersistedTopicBearingTurnCount ?? countTopicBearingTurns(sampleMessages);
|
|
1628
1727
|
const s09ForkedContextSeed = request.forkedContext?.enabled ? request.forkedContext : undefined;
|
|
1629
1728
|
const s09ForkedParentPressure = typeof s09ForkedContextSeed?.parentPressureFraction === 'number'
|
|
1630
1729
|
&& Number.isFinite(s09ForkedContextSeed.parentPressureFraction)
|
|
@@ -1638,6 +1737,7 @@ export class Compositor {
|
|
|
1638
1737
|
const evictionLifecyclePolicy = resolveAdaptiveLifecyclePolicy({
|
|
1639
1738
|
pressureFraction: s09EvictionPolicyPressure,
|
|
1640
1739
|
userTurnCount: s09ObservedUserTurnCount,
|
|
1740
|
+
topicBearingTurnCount: s09TopicBearingTurnCount,
|
|
1641
1741
|
explicitNewSession: isExplicitNewSessionPrompt(request.prompt ?? null),
|
|
1642
1742
|
forkedContext: Boolean(s09ForkedContextSeed),
|
|
1643
1743
|
forkedParentPressureFraction: s09ForkedParentPressure,
|
|
@@ -1775,6 +1875,9 @@ export class Compositor {
|
|
|
1775
1875
|
// C1: total tool-chain degradation counters across history budget-fit and safety-valve passes.
|
|
1776
1876
|
let c1CoEjections = 0;
|
|
1777
1877
|
let c1StubReplacements = 0;
|
|
1878
|
+
let literalAntecedentGuardHits = 0;
|
|
1879
|
+
const literalAntecedentGuardMessages = new Set();
|
|
1880
|
+
const literalAntecedentGuardHitMessages = new Set();
|
|
1778
1881
|
// Hoisted: activeTopicId/name resolved inside history block, used for window dual-write (VS-1) and wiki page injection
|
|
1779
1882
|
let composedActiveTopicId;
|
|
1780
1883
|
let composedActiveTopicName;
|
|
@@ -1824,20 +1927,58 @@ export class Compositor {
|
|
|
1824
1927
|
composedActiveTopicName = activeTopic?.name;
|
|
1825
1928
|
const rawHistoryMessages = await this.getHistory(request.agentId, request.sessionKey, s4EffectiveDepth, // Sprint 4: adaptive depth (replaces fixed maxHistoryMessages)
|
|
1826
1929
|
store, activeTopicId, fenceMessageId, activeContext);
|
|
1930
|
+
// Continuity guard: force a small tail of meaningful transcript rows into
|
|
1931
|
+
// the candidate window before budget selection. Tool carrier rows can have
|
|
1932
|
+
// empty text_content; in dense tool loops they can consume raw history depth
|
|
1933
|
+
// and push the immediate conversational antecedent out of the selected
|
|
1934
|
+
// window. The full tool stream still comes from getHistory(); this guard
|
|
1935
|
+
// only repairs the human-readable transcript tail.
|
|
1936
|
+
let continuityTail = [];
|
|
1937
|
+
try {
|
|
1938
|
+
const conversation = store.getConversation(request.sessionKey);
|
|
1939
|
+
if (conversation) {
|
|
1940
|
+
continuityTail = store.getRecentMeaningfulMessages(conversation.id, 8, fenceMessageId);
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
catch {
|
|
1944
|
+
continuityTail = [];
|
|
1945
|
+
}
|
|
1946
|
+
const mergedRawHistory = continuityTail.length > 0
|
|
1947
|
+
? [...rawHistoryMessages, ...continuityTail].sort((a, b) => {
|
|
1948
|
+
const ai = a.messageIndex ?? 0;
|
|
1949
|
+
const bi = b.messageIndex ?? 0;
|
|
1950
|
+
return ai - bi;
|
|
1951
|
+
})
|
|
1952
|
+
: rawHistoryMessages;
|
|
1827
1953
|
// Deduplicate history by StoredMessage.id (second line of defense after
|
|
1828
1954
|
// pushHistory() tail-check dedup). Guards against any duplicates that
|
|
1829
1955
|
// slipped through the warm path — e.g. bootstrap re-runs on existing sessions.
|
|
1830
|
-
|
|
1831
|
-
|
|
1956
|
+
// If the continuity transcript projection overlaps with full runtime
|
|
1957
|
+
// history, prefer the full row. Transcript projections intentionally null
|
|
1958
|
+
// tool_calls/tool_results and must never replace a tool-bearing history row.
|
|
1959
|
+
const historyById = new Map();
|
|
1960
|
+
const historyMessagesNoId = [];
|
|
1961
|
+
const rowScore = (m) => (m.toolCalls != null ? 2 : 0) + (m.toolResults != null ? 2 : 0) + (m.textContent ? 1 : 0);
|
|
1962
|
+
for (const m of mergedRawHistory) {
|
|
1832
1963
|
const sm = m;
|
|
1833
|
-
if (sm.id
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1964
|
+
if (sm.id == null) {
|
|
1965
|
+
historyMessagesNoId.push(m);
|
|
1966
|
+
continue;
|
|
1967
|
+
}
|
|
1968
|
+
const existing = historyById.get(sm.id);
|
|
1969
|
+
if (!existing || rowScore(sm) > rowScore(existing)) {
|
|
1970
|
+
historyById.set(sm.id, sm);
|
|
1837
1971
|
}
|
|
1838
|
-
|
|
1972
|
+
}
|
|
1973
|
+
const historyMessages = [...historyMessagesNoId, ...historyById.values()].sort((a, b) => {
|
|
1974
|
+
const ai = a.messageIndex ?? 0;
|
|
1975
|
+
const bi = b.messageIndex ?? 0;
|
|
1976
|
+
return ai - bi;
|
|
1839
1977
|
});
|
|
1840
1978
|
s09ObservedUserTurnCount = Math.max(s09ObservedUserTurnCount, historyMessages.filter(m => m.role === 'user').length);
|
|
1979
|
+
if (s09PersistedTopicBearingTurnCount == null) {
|
|
1980
|
+
s09TopicBearingTurnCount = Math.max(s09TopicBearingTurnCount, countTopicBearingTurns(historyMessages));
|
|
1981
|
+
}
|
|
1841
1982
|
composeTopicMessageCount = historyMessages.length;
|
|
1842
1983
|
composeTopicStampedMessageCount = historyMessages.filter(m => typeof m.topicId === 'string').length;
|
|
1843
1984
|
// ── Transform-first: apply gradient tool treatment BEFORE budget math ──
|
|
@@ -1871,6 +2012,12 @@ export class Compositor {
|
|
|
1871
2012
|
// drop inactive-topic non-tool clusters first when an active topic is
|
|
1872
2013
|
// known. Bootstrap/warmup/steady reproduce the historical newest-first
|
|
1873
2014
|
// sweep exactly (preferTopicAwareDrop=false → evictedByPlan stays empty).
|
|
2015
|
+
const literalAntecedentGuardIndices = resolveLiteralAntecedentGuardClusterIndices(budgetClusters, {
|
|
2016
|
+
enabled: evictionLifecyclePolicy.band !== 'critical',
|
|
2017
|
+
currentPrompt: request.prompt,
|
|
2018
|
+
maxMessages: LITERAL_ANTECEDENT_GUARD_MAX_MESSAGES,
|
|
2019
|
+
maxTokens: LITERAL_ANTECEDENT_GUARD_MAX_TOKENS,
|
|
2020
|
+
});
|
|
1874
2021
|
const adaptiveOrdering = orderClustersForAdaptiveEviction(budgetClusters, evictionLifecyclePolicy, { activeTopicId });
|
|
1875
2022
|
adaptiveEvictionTopicAwareEligibleClusters = adaptiveOrdering.telemetry.topicAwareEligibleClusters;
|
|
1876
2023
|
adaptiveEvictionProtectedClusters = adaptiveOrdering.telemetry.protectedClusters;
|
|
@@ -1897,6 +2044,16 @@ export class Compositor {
|
|
|
1897
2044
|
break;
|
|
1898
2045
|
if (adaptiveOrdering.protectedIndices.has(idx))
|
|
1899
2046
|
continue;
|
|
2047
|
+
if (literalAntecedentGuardIndices.has(idx)) {
|
|
2048
|
+
for (const msg of budgetClusters[idx].messages) {
|
|
2049
|
+
literalAntecedentGuardMessages.add(msg);
|
|
2050
|
+
if (!literalAntecedentGuardHitMessages.has(msg)) {
|
|
2051
|
+
literalAntecedentGuardHitMessages.add(msg);
|
|
2052
|
+
literalAntecedentGuardHits++;
|
|
2053
|
+
}
|
|
2054
|
+
}
|
|
2055
|
+
continue;
|
|
2056
|
+
}
|
|
1900
2057
|
evictedByPlan.add(idx);
|
|
1901
2058
|
projectedTokens -= budgetClusters[idx].tokenCost;
|
|
1902
2059
|
}
|
|
@@ -1907,12 +2064,29 @@ export class Compositor {
|
|
|
1907
2064
|
if (evictedByPlan.has(i))
|
|
1908
2065
|
continue;
|
|
1909
2066
|
const cluster = budgetClusters[i];
|
|
2067
|
+
const isLiteralAntecedentGuarded = literalAntecedentGuardIndices.has(i);
|
|
1910
2068
|
if (historyTokens + cluster.tokenCost > historyFillCap && includedClusters.length > 0) {
|
|
2069
|
+
if (isLiteralAntecedentGuarded) {
|
|
2070
|
+
includedClusters.unshift(cluster);
|
|
2071
|
+
historyTokens += cluster.tokenCost;
|
|
2072
|
+
for (const msg of cluster.messages) {
|
|
2073
|
+
literalAntecedentGuardMessages.add(msg);
|
|
2074
|
+
if (!literalAntecedentGuardHitMessages.has(msg)) {
|
|
2075
|
+
literalAntecedentGuardHitMessages.add(msg);
|
|
2076
|
+
literalAntecedentGuardHits++;
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
2079
|
+
continue;
|
|
2080
|
+
}
|
|
1911
2081
|
truncationCutIndex = i;
|
|
1912
2082
|
break;
|
|
1913
2083
|
}
|
|
1914
2084
|
includedClusters.unshift(cluster);
|
|
1915
2085
|
historyTokens += cluster.tokenCost;
|
|
2086
|
+
if (isLiteralAntecedentGuarded) {
|
|
2087
|
+
for (const msg of cluster.messages)
|
|
2088
|
+
literalAntecedentGuardMessages.add(msg);
|
|
2089
|
+
}
|
|
1916
2090
|
}
|
|
1917
2091
|
if (truncationCutIndex >= 0 || evictedByPlan.size > 0) {
|
|
1918
2092
|
const droppedIndices = [];
|
|
@@ -2403,6 +2577,7 @@ export class Compositor {
|
|
|
2403
2577
|
const composeLifecyclePolicy = resolveAdaptiveLifecyclePolicy({
|
|
2404
2578
|
pressureFraction: s09ComposePolicyPressure,
|
|
2405
2579
|
userTurnCount: s09ObservedUserTurnCount,
|
|
2580
|
+
topicBearingTurnCount: s09TopicBearingTurnCount,
|
|
2406
2581
|
explicitNewSession: isExplicitNewSessionPrompt(request.prompt ?? this.getLastUserMessage(messages)),
|
|
2407
2582
|
forkedContext: Boolean(s09ForkedContextSeed),
|
|
2408
2583
|
forkedParentPressureFraction: s09ForkedParentPressure,
|
|
@@ -2411,6 +2586,8 @@ export class Compositor {
|
|
|
2411
2586
|
const recallBreadth = scaleRecallBreadth(remaining, composeLifecyclePolicy.smartRecallMultiplier);
|
|
2412
2587
|
let diagAdaptiveRecallBudgetTokens;
|
|
2413
2588
|
let diagAdaptiveRecallCandidateLimit;
|
|
2589
|
+
let diagComposeAdjacencyBoosted = 0;
|
|
2590
|
+
let diagComposeAdjacencyDeltaTotalMs = 0;
|
|
2414
2591
|
if (request.includeSemanticRecall !== false && remaining > 500 && (this.vectorStore || libDb)) {
|
|
2415
2592
|
const lastUserMsg = request.prompt?.trim() || this.getLastUserMessage(messages);
|
|
2416
2593
|
if (lastUserMsg) {
|
|
@@ -2435,6 +2612,9 @@ export class Compositor {
|
|
|
2435
2612
|
diagRerankerStatus = ev.status;
|
|
2436
2613
|
diagRerankerCandidates = ev.candidates;
|
|
2437
2614
|
diagRerankerProvider = ev.provider;
|
|
2615
|
+
}, (ev) => {
|
|
2616
|
+
diagComposeAdjacencyBoosted += ev.boostedCount;
|
|
2617
|
+
diagComposeAdjacencyDeltaTotalMs += ev.averageDeltaMs * ev.boostedCount;
|
|
2438
2618
|
}, recallBreadth.candidateLimit);
|
|
2439
2619
|
if (semanticContent) {
|
|
2440
2620
|
const tokens = estimateTokens(semanticContent);
|
|
@@ -2585,7 +2765,7 @@ export class Compositor {
|
|
|
2585
2765
|
}
|
|
2586
2766
|
const fallbackContent = await Promise.race([
|
|
2587
2767
|
this.buildSemanticRecall(lastMsg, request.agentId, recallBreadth.fallbackBudgetTokens, libDb || undefined, undefined, contextFingerprints, // C2: skip results already in Active Facts
|
|
2588
|
-
undefined, recallBreadth.candidateLimit),
|
|
2768
|
+
undefined, undefined, recallBreadth.candidateLimit),
|
|
2589
2769
|
new Promise((_, reject) => setTimeout(() => reject(new Error('fallback_knn_timeout')), 3000)),
|
|
2590
2770
|
]);
|
|
2591
2771
|
if (fallbackContent) {
|
|
@@ -2768,6 +2948,15 @@ export class Compositor {
|
|
|
2768
2948
|
// Don't trim the last user message (current prompt).
|
|
2769
2949
|
if (i === messages.length - 1 && messages[i].role === 'user')
|
|
2770
2950
|
break;
|
|
2951
|
+
// Packet 5: preserve the bounded immediate antecedent for literal follow-ups.
|
|
2952
|
+
if (literalAntecedentGuardMessages.has(messages[i])) {
|
|
2953
|
+
if (!literalAntecedentGuardHitMessages.has(messages[i])) {
|
|
2954
|
+
literalAntecedentGuardHitMessages.add(messages[i]);
|
|
2955
|
+
literalAntecedentGuardHits++;
|
|
2956
|
+
}
|
|
2957
|
+
i++;
|
|
2958
|
+
continue;
|
|
2959
|
+
}
|
|
2771
2960
|
// Sprint 4: Don't trim the volatile context block (dynamicBoundary marker).
|
|
2772
2961
|
const meta = messages[i].metadata;
|
|
2773
2962
|
if (meta?.dynamicBoundary) {
|
|
@@ -3040,6 +3229,9 @@ export class Compositor {
|
|
|
3040
3229
|
adaptiveSmartRecallMultiplier: composeLifecyclePolicy.smartRecallMultiplier,
|
|
3041
3230
|
adaptiveTrimSoftTarget: composeLifecyclePolicy.trimSoftTarget,
|
|
3042
3231
|
adaptiveCompactionTargetFraction: composeLifecyclePolicy.compactionTargetFraction,
|
|
3232
|
+
adaptiveProtectedWarmingFraction: composeLifecyclePolicy.protectedWarmingMetadata.isProtected
|
|
3233
|
+
? composeLifecyclePolicy.protectedWarmingMetadata.floor
|
|
3234
|
+
: undefined,
|
|
3043
3235
|
adaptiveBreadcrumbPackage: composeLifecyclePolicy.emitBreadcrumbPackage,
|
|
3044
3236
|
adaptiveTopicCentroidEviction: composeLifecyclePolicy.enableTopicCentroidEviction,
|
|
3045
3237
|
adaptiveProactiveCompaction: composeLifecyclePolicy.triggerProactiveCompaction,
|
|
@@ -3053,6 +3245,11 @@ export class Compositor {
|
|
|
3053
3245
|
adaptiveEvictionProtectedClusters,
|
|
3054
3246
|
adaptiveEvictionTopicIdCoveragePct,
|
|
3055
3247
|
adaptiveEvictionBypassReason,
|
|
3248
|
+
composeAdjacencyBoosted: diagComposeAdjacencyBoosted > 0 ? diagComposeAdjacencyBoosted : undefined,
|
|
3249
|
+
composeAdjacencyAverageDeltaMs: diagComposeAdjacencyBoosted > 0
|
|
3250
|
+
? Math.round(diagComposeAdjacencyDeltaTotalMs / diagComposeAdjacencyBoosted)
|
|
3251
|
+
: undefined,
|
|
3252
|
+
evictionAdjacencyGuardHits: literalAntecedentGuardHits > 0 ? literalAntecedentGuardHits : undefined,
|
|
3056
3253
|
composeTopicSource,
|
|
3057
3254
|
composeTopicState,
|
|
3058
3255
|
composeTopicMessageCount,
|
|
@@ -3092,6 +3289,9 @@ export class Compositor {
|
|
|
3092
3289
|
compactionEligibleRatio: diagCompactionEligibleRatio,
|
|
3093
3290
|
compactionProcessedCount: diagCompactionProcessedCount,
|
|
3094
3291
|
};
|
|
3292
|
+
if (literalAntecedentGuardHits > 0) {
|
|
3293
|
+
diagnostics.literalAntecedentGuardHits = literalAntecedentGuardHits;
|
|
3294
|
+
}
|
|
3095
3295
|
if (pressureHigh) {
|
|
3096
3296
|
warnings.push(`SESSION_PRESSURE_HIGH: avg_turn_cost=${avgTurnCost} tokens, dynamic reserve capped at ${Math.round(dynamicReserve * 100)}%`);
|
|
3097
3297
|
}
|
|
@@ -3203,7 +3403,7 @@ export class Compositor {
|
|
|
3203
3403
|
catch (error) {
|
|
3204
3404
|
console.warn(`[hypermem:compositor] composition snapshot write skipped: ${error.message}`);
|
|
3205
3405
|
}
|
|
3206
|
-
console.log(`[hypermem:compose] agent=${request.agentId} triggers=${diagTriggerHits} fallback=${diagTriggerFallbackUsed} facts=${diagFactsIncluded} semantic=${diagSemanticResults} chunks=${diagDocChunkCollections} scopeFiltered=${diagScopeFiltered} mode=${diagRetrievalMode} crossTopicKeystones=${diagCrossTopicKeystones} c2_degradations=${c2ArtifactDegradations} c2_threshold=${c2ArtifactThresholdTokens}`);
|
|
3406
|
+
console.log(`[hypermem:compose] agent=${request.agentId} triggers=${diagTriggerHits} fallback=${diagTriggerFallbackUsed} facts=${diagFactsIncluded} semantic=${diagSemanticResults} chunks=${diagDocChunkCollections} scopeFiltered=${diagScopeFiltered} mode=${diagRetrievalMode} crossTopicKeystones=${diagCrossTopicKeystones} c2_degradations=${c2ArtifactDegradations} c2_threshold=${c2ArtifactThresholdTokens} literal_antecedent_guard_hits=${literalAntecedentGuardHits} adjacency_boosted=${diagComposeAdjacencyBoosted} adjacency_avg_delta_ms=${diagComposeAdjacencyBoosted > 0 ? Math.round(diagComposeAdjacencyDeltaTotalMs / diagComposeAdjacencyBoosted) : 0} eviction_adjacency_guard_hits=${literalAntecedentGuardHits}`);
|
|
3207
3407
|
return {
|
|
3208
3408
|
messages: outputMessages,
|
|
3209
3409
|
tokenCount: totalTokens,
|
|
@@ -3454,23 +3654,37 @@ export class Compositor {
|
|
|
3454
3654
|
let historyToWrite = transformedHistory;
|
|
3455
3655
|
if (tokenBudget && tokenBudget > 0) {
|
|
3456
3656
|
const budgetCap = gradientAssembleBudget;
|
|
3657
|
+
const protectedFloor = resolveAfterTurnProtectedWarmingFloor(tokenBudget, trimSoftTarget);
|
|
3457
3658
|
let runningTokens = 0;
|
|
3659
|
+
let protectedClustersKept = 0;
|
|
3458
3660
|
const clusters = clusterNeutralMessages(transformedHistory);
|
|
3459
3661
|
const cappedClusters = [];
|
|
3460
3662
|
// Walk newest-first, keep whole clusters so tool-call/result pairs survive together.
|
|
3663
|
+
// Packet 3: during bootstrap/warmup, do not let cluster-boundary underfill
|
|
3664
|
+
// cut the refreshed hot window below the protected warming floor. This may
|
|
3665
|
+
// keep one or more whole older clusters past the soft cap, but only until
|
|
3666
|
+
// the protected floor is satisfied. Elevated/high/critical bands get no
|
|
3667
|
+
// floor, so the existing cap behavior remains intact under real pressure.
|
|
3461
3668
|
for (let i = clusters.length - 1; i >= 0; i--) {
|
|
3462
3669
|
const cluster = clusters[i];
|
|
3463
|
-
|
|
3670
|
+
const wouldExceedCap = runningTokens + cluster.tokenCost > budgetCap && cappedClusters.length > 0;
|
|
3671
|
+
const belowProtectedFloor = protectedFloor.floorTokens > 0 && runningTokens < protectedFloor.floorTokens;
|
|
3672
|
+
if (wouldExceedCap && !belowProtectedFloor)
|
|
3464
3673
|
break;
|
|
3674
|
+
if (wouldExceedCap && belowProtectedFloor)
|
|
3675
|
+
protectedClustersKept++;
|
|
3465
3676
|
cappedClusters.unshift(cluster);
|
|
3466
3677
|
runningTokens += cluster.tokenCost;
|
|
3467
|
-
if (runningTokens >= budgetCap)
|
|
3678
|
+
if (runningTokens >= budgetCap && runningTokens >= protectedFloor.floorTokens)
|
|
3468
3679
|
break;
|
|
3469
3680
|
}
|
|
3470
3681
|
historyToWrite = cappedClusters.flatMap(cluster => cluster.messages);
|
|
3471
3682
|
if (historyToWrite.length < transformedHistory.length) {
|
|
3683
|
+
const protectedNote = protectedFloor.floorTokens > 0
|
|
3684
|
+
? `, protectedFloor=${protectedFloor.floorTokens}, protectedClustersKept=${protectedClustersKept}`
|
|
3685
|
+
: '';
|
|
3472
3686
|
console.log(`[hypermem] refreshRedisGradient: cluster-capped ${transformedHistory.length}→${historyToWrite.length} messages ` +
|
|
3473
|
-
`for ${agentId}/${sessionKey} (budgetCap=${budgetCap}, tokenCost=${runningTokens})`);
|
|
3687
|
+
`for ${agentId}/${sessionKey} (budgetCap=${budgetCap}, tokenCost=${runningTokens}${protectedNote})`);
|
|
3474
3688
|
}
|
|
3475
3689
|
}
|
|
3476
3690
|
await this.cache.replaceHistory(agentId, sessionKey, historyToWrite, refreshHistoryLimit);
|
|
@@ -3706,7 +3920,7 @@ export class Compositor {
|
|
|
3706
3920
|
*/
|
|
3707
3921
|
async buildSemanticRecall(userMessage, agentId, maxTokens, libraryDb, precomputedEmbedding, existingFingerprints, // C2: skip results already in Active Facts
|
|
3708
3922
|
onRerankerTelemetry, // Sprint 1: surface reranker status at assemble level
|
|
3709
|
-
resultLimit) {
|
|
3923
|
+
onAdjacencyTelemetry, resultLimit) {
|
|
3710
3924
|
const libDb = libraryDb || this.libraryDb;
|
|
3711
3925
|
if (!libDb && !this.vectorStore)
|
|
3712
3926
|
return null;
|
|
@@ -3736,6 +3950,7 @@ export class Compositor {
|
|
|
3736
3950
|
rerankerTopK: this.rerankerTopK,
|
|
3737
3951
|
// Sprint 1: thread reranker telemetry into compose diagnostics
|
|
3738
3952
|
onRerankerTelemetry,
|
|
3953
|
+
onAdjacencyTelemetry,
|
|
3739
3954
|
});
|
|
3740
3955
|
if (results.length === 0)
|
|
3741
3956
|
return null;
|
|
@@ -3861,9 +4076,6 @@ export class Compositor {
|
|
|
3861
4076
|
* Build cross-session context by finding recent activity
|
|
3862
4077
|
* in other sessions for this agent.
|
|
3863
4078
|
*/
|
|
3864
|
-
// TODO Phase 1: buildCrossSessionContext queries OTHER conversations. Each has its
|
|
3865
|
-
// own compaction fence. Per-conversation fence filtering should be added here so
|
|
3866
|
-
// zombie messages from other sessions don't leak into cross-session context.
|
|
3867
4079
|
buildCrossSessionContext(agentId, currentSessionKey, db, _libraryDb, existingFingerprints // C3: skip entries already in facts/semantic recall
|
|
3868
4080
|
) {
|
|
3869
4081
|
const conversation = db.prepare('SELECT id FROM conversations WHERE session_key = ?').get(currentSessionKey);
|
|
@@ -3873,10 +4085,14 @@ export class Compositor {
|
|
|
3873
4085
|
SELECT m.text_content, m.role, c.channel_type, m.created_at
|
|
3874
4086
|
FROM messages m
|
|
3875
4087
|
JOIN conversations c ON m.conversation_id = c.id
|
|
4088
|
+
LEFT JOIN compaction_fences cf ON cf.conversation_id = m.conversation_id
|
|
3876
4089
|
WHERE c.agent_id = ?
|
|
3877
4090
|
AND m.conversation_id != ?
|
|
3878
4091
|
AND c.status = 'active'
|
|
4092
|
+
AND (cf.fence_message_id IS NULL OR m.id >= cf.fence_message_id)
|
|
4093
|
+
AND m.role IN ('user', 'assistant')
|
|
3879
4094
|
AND m.text_content IS NOT NULL
|
|
4095
|
+
AND trim(m.text_content) != ''
|
|
3880
4096
|
AND m.is_heartbeat = 0
|
|
3881
4097
|
ORDER BY m.created_at DESC
|
|
3882
4098
|
LIMIT 10
|
|
@@ -4014,9 +4230,10 @@ export class Compositor {
|
|
|
4014
4230
|
AND m.id < ?
|
|
4015
4231
|
${fenceClause}
|
|
4016
4232
|
${contextClause}
|
|
4233
|
+
AND m.role IN ('user', 'assistant')
|
|
4017
4234
|
AND m.text_content IS NOT NULL
|
|
4235
|
+
AND trim(m.text_content) != ''
|
|
4018
4236
|
AND m.is_heartbeat = 0
|
|
4019
|
-
AND m.text_content != ''
|
|
4020
4237
|
LIMIT 200
|
|
4021
4238
|
`;
|
|
4022
4239
|
let candidateRows;
|
|
@@ -4046,9 +4263,10 @@ export class Compositor {
|
|
|
4046
4263
|
AND m.id < ?
|
|
4047
4264
|
${fenceClause}
|
|
4048
4265
|
${contextClause}
|
|
4266
|
+
AND m.role IN ('user', 'assistant')
|
|
4049
4267
|
AND m.text_content IS NOT NULL
|
|
4268
|
+
AND trim(m.text_content) != ''
|
|
4050
4269
|
AND m.is_heartbeat = 0
|
|
4051
|
-
AND m.text_content != ''
|
|
4052
4270
|
AND m.id IN (
|
|
4053
4271
|
SELECT rowid FROM messages_fts
|
|
4054
4272
|
WHERE messages_fts MATCH ?
|
|
@@ -4187,8 +4405,9 @@ export class Compositor {
|
|
|
4187
4405
|
AND m.topic_id = ?
|
|
4188
4406
|
${topicFenceClause}
|
|
4189
4407
|
${topicContextClause}
|
|
4408
|
+
AND m.role IN ('user', 'assistant')
|
|
4190
4409
|
AND m.text_content IS NOT NULL
|
|
4191
|
-
AND m.text_content != ''
|
|
4410
|
+
AND trim(m.text_content) != ''
|
|
4192
4411
|
AND m.is_heartbeat = 0
|
|
4193
4412
|
ORDER BY m.message_index DESC
|
|
4194
4413
|
LIMIT 50
|
|
@@ -25,6 +25,12 @@ export interface RerankerTelemetry {
|
|
|
25
25
|
/** Outcome for this invocation. */
|
|
26
26
|
status: RerankerStatus;
|
|
27
27
|
}
|
|
28
|
+
export interface AdjacencyTelemetry {
|
|
29
|
+
/** Number of candidates boosted by adjacency scoring. */
|
|
30
|
+
boostedCount: number;
|
|
31
|
+
/** Average antecedent-to-successor wall-clock delta in milliseconds. */
|
|
32
|
+
averageDeltaMs: number;
|
|
33
|
+
}
|
|
28
34
|
export interface HybridSearchResult {
|
|
29
35
|
sourceTable: string;
|
|
30
36
|
sourceId: number;
|
|
@@ -86,6 +92,8 @@ export interface HybridSearchOptions {
|
|
|
86
92
|
rerankerTimeoutMs?: number;
|
|
87
93
|
/** Optional telemetry sink. When omitted, falls back to emitRerankerLog. */
|
|
88
94
|
onRerankerTelemetry?: (ev: RerankerTelemetry) => void;
|
|
95
|
+
/** Optional metadata-only telemetry for adjacency boosts. */
|
|
96
|
+
onAdjacencyTelemetry?: (ev: AdjacencyTelemetry) => void;
|
|
89
97
|
}
|
|
90
98
|
/**
|
|
91
99
|
* Build an FTS5 query from a natural language string.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hybrid-retrieval.d.ts","sourceRoot":"","sources":["../src/hybrid-retrieval.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAsB,MAAM,mBAAmB,CAAC;AACzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAQtD,MAAM,MAAM,cAAc,GACtB,SAAS,GACT,oBAAoB,GACpB,wBAAwB,GACxB,QAAQ,GACR,SAAS,CAAC;AAEd,MAAM,WAAW,iBAAiB;IAChC,2FAA2F;IAC3F,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,4DAA4D;IAC5D,UAAU,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,MAAM,EAAE,cAAc,CAAC;CACxB;AAcD,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,OAAO,EAAE,CAAC,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAmB;IAClC,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uFAAuF;IACvF,oBAAoB,CAAC,EAAE,YAAY,CAAC;IACpC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACnC;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B;;;OAGG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,4EAA4E;IAC5E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,4EAA4E;IAC5E,mBAAmB,CAAC,EAAE,CAAC,EAAE,EAAE,iBAAiB,KAAK,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"hybrid-retrieval.d.ts","sourceRoot":"","sources":["../src/hybrid-retrieval.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAsB,MAAM,mBAAmB,CAAC;AACzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAQtD,MAAM,MAAM,cAAc,GACtB,SAAS,GACT,oBAAoB,GACpB,wBAAwB,GACxB,QAAQ,GACR,SAAS,CAAC;AAEd,MAAM,WAAW,iBAAiB;IAChC,2FAA2F;IAC3F,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,4DAA4D;IAC5D,UAAU,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,yDAAyD;IACzD,YAAY,EAAE,MAAM,CAAC;IACrB,wEAAwE;IACxE,cAAc,EAAE,MAAM,CAAC;CACxB;AAcD,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,OAAO,EAAE,CAAC,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAmB;IAClC,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uFAAuF;IACvF,oBAAoB,CAAC,EAAE,YAAY,CAAC;IACpC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACnC;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B;;;OAGG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,4EAA4E;IAC5E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,4EAA4E;IAC5E,mBAAmB,CAAC,EAAE,CAAC,EAAE,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACtD,6DAA6D;IAC7D,oBAAoB,CAAC,EAAE,CAAC,EAAE,EAAE,kBAAkB,KAAK,IAAI,CAAC;CACzD;AAqBD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAiBnD;AAkUD;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,SAAS,EAAE,YAAY,EACvB,WAAW,EAAE,WAAW,GAAG,IAAI,EAC/B,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,mBAAmB,GACzB,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAqJ/B"}
|