@psiclawops/hypermem 0.7.0 → 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-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/index.d.ts +70 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +405 -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 +236 -1
- 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/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 +235 -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
|
@@ -26,6 +26,9 @@ import { EpisodeStore } from './episode-store.js';
|
|
|
26
26
|
import { TopicStore } from './topic-store.js';
|
|
27
27
|
import { KnowledgeStore } from './knowledge-store.js';
|
|
28
28
|
import { TemporalStore } from './temporal-store.js';
|
|
29
|
+
import { ContradictionDetector } from './contradiction-detector.js';
|
|
30
|
+
import { ContradictionAuditStore } from './contradiction-audit-store.js';
|
|
31
|
+
import { DEFAULT_CONTRADICTION_POLICY } from './contradiction-resolution-policy.js';
|
|
29
32
|
import { isSafeForSharedVisibility } from './secret-scanner.js';
|
|
30
33
|
// ─── Agent-to-Domain Map ────────────────────────────────────────
|
|
31
34
|
// Maps well-known agent IDs to their primary domain.
|
|
@@ -34,27 +37,27 @@ import { isSafeForSharedVisibility } from './secret-scanner.js';
|
|
|
34
37
|
// returns results. New agents default to 'general'.
|
|
35
38
|
//
|
|
36
39
|
// ── EXAMPLE DATA ──────────────────────────────────────────────────
|
|
37
|
-
// The agent names below (
|
|
40
|
+
// The agent names below (alice, director1, etc.) are PLACEHOLDERS.
|
|
38
41
|
// Replace them with your own agent IDs and domain labels to match
|
|
39
42
|
// your fleet. Single-agent installs don't need to edit this:
|
|
40
43
|
// unknown agents fall through to 'general' automatically.
|
|
41
44
|
// See INSTALL.md § "Configure your fleet" for details.
|
|
42
45
|
// ─────────────────────────────────────────────────────────────────
|
|
43
46
|
const AGENT_DOMAIN_MAP = {
|
|
44
|
-
|
|
47
|
+
alice: 'infrastructure',
|
|
45
48
|
director2: 'infrastructure',
|
|
46
49
|
director1: 'infrastructure',
|
|
47
50
|
director3: 'infrastructure',
|
|
48
|
-
|
|
51
|
+
bob: 'product',
|
|
49
52
|
director4: 'product',
|
|
50
53
|
director5: 'product',
|
|
51
54
|
director6: 'product',
|
|
52
|
-
|
|
55
|
+
dave: 'security',
|
|
53
56
|
director7: 'security',
|
|
54
57
|
director8: 'security',
|
|
55
58
|
agent4: 'ux',
|
|
56
|
-
|
|
57
|
-
|
|
59
|
+
carol: 'governance',
|
|
60
|
+
oscar: 'strategy',
|
|
58
61
|
specialist1: 'development',
|
|
59
62
|
specialist2: 'communications',
|
|
60
63
|
main: 'general',
|
|
@@ -91,7 +94,7 @@ function extractFactCandidates(content) {
|
|
|
91
94
|
// Preference patterns — medium confidence (0.60)
|
|
92
95
|
const preferencePatterns = [
|
|
93
96
|
/(?:prefer|always use|never use|don't use|avoid) (.{10,150})/gi,
|
|
94
|
-
/(?:operator
|
|
97
|
+
/(?:operator) (?:wants|prefers|likes|hates|dislikes) (.{10,150})/gi,
|
|
95
98
|
];
|
|
96
99
|
// Operational patterns: deployments, incidents, fixes — high confidence (0.70)
|
|
97
100
|
const operationalPatterns = [
|
|
@@ -145,7 +148,7 @@ const OPERATIONAL_BOILERPLATE = [
|
|
|
145
148
|
/still\s*waiting/i,
|
|
146
149
|
/will\s*pick\s*(it\s*)?up\s*(on\s*(next|the))?/i,
|
|
147
150
|
/message\s*is\s*in\s*(his|her|their|the)\s*queue/i,
|
|
148
|
-
/sent\s+to\s+(
|
|
151
|
+
/sent\s+to\s+(carol|bob|agent4|dave|oscar|alice)/i,
|
|
149
152
|
/dispatched\s+(it\s+)?to/i,
|
|
150
153
|
/timed\s*out\s*after/i,
|
|
151
154
|
/\bNO_REPLY\b/,
|
|
@@ -390,7 +393,7 @@ function detectTopic(content) {
|
|
|
390
393
|
if (!content || content.length < 50)
|
|
391
394
|
return null;
|
|
392
395
|
// Product/project name detection
|
|
393
|
-
const productMatch = content.match(/\b(HyperMem|ClawText|
|
|
396
|
+
const productMatch = content.match(/\b(HyperMem|ClawText|dashboard|canvas|council|automation|OpenClaw|dispatch)\b/i);
|
|
394
397
|
if (productMatch)
|
|
395
398
|
return productMatch[1];
|
|
396
399
|
// Infrastructure topic detection
|
|
@@ -411,6 +414,8 @@ export class BackgroundIndexer {
|
|
|
411
414
|
getCursor;
|
|
412
415
|
config;
|
|
413
416
|
dreamerConfig;
|
|
417
|
+
globalWritePolicy;
|
|
418
|
+
contradictionPolicy;
|
|
414
419
|
intervalHandle = null;
|
|
415
420
|
running = false;
|
|
416
421
|
vectorStore = null;
|
|
@@ -420,7 +425,9 @@ export class BackgroundIndexer {
|
|
|
420
425
|
consecutiveFailures = 0;
|
|
421
426
|
/** True when the indexer is running in backoff mode due to repeated failures. */
|
|
422
427
|
inBackoff = false;
|
|
423
|
-
|
|
428
|
+
_conversationLastProcessed = new Map();
|
|
429
|
+
lastMaintenanceDiagnostics = null;
|
|
430
|
+
constructor(config, getMessageDb, getLibraryDb, listAgents, getCursor, dreamerConfig, globalWritePolicy, contradictionPolicy) {
|
|
424
431
|
this.getMessageDb = getMessageDb;
|
|
425
432
|
this.getLibraryDb = getLibraryDb;
|
|
426
433
|
this.listAgents = listAgents;
|
|
@@ -451,8 +458,13 @@ export class BackgroundIndexer {
|
|
|
451
458
|
periodicInterval: config?.periodicInterval ?? 60000, // 1 minute
|
|
452
459
|
batchSize: config?.batchSize ?? 128,
|
|
453
460
|
maxMessagesPerTick: config?.maxMessagesPerTick ?? 500,
|
|
461
|
+
maxActiveConversations: config?.maxActiveConversations ?? 5,
|
|
462
|
+
recentConversationCooldownMs: config?.recentConversationCooldownMs ?? 30000,
|
|
463
|
+
maxCandidatesPerPass: config?.maxCandidatesPerPass ?? 200,
|
|
454
464
|
};
|
|
455
465
|
this.dreamerConfig = dreamerConfig ?? {};
|
|
466
|
+
this.globalWritePolicy = globalWritePolicy ?? 'deny';
|
|
467
|
+
this.contradictionPolicy = contradictionPolicy ?? DEFAULT_CONTRADICTION_POLICY;
|
|
456
468
|
}
|
|
457
469
|
/**
|
|
458
470
|
* Set the vector store for embedding new facts/episodes at index time.
|
|
@@ -686,27 +698,72 @@ export class BackgroundIndexer {
|
|
|
686
698
|
}
|
|
687
699
|
}
|
|
688
700
|
// Run proactive passes on each agent's message DB
|
|
701
|
+
const maintStart = Date.now();
|
|
702
|
+
let maintConsidered = 0;
|
|
703
|
+
let maintSkipped = 0;
|
|
704
|
+
let maintScanned = 0;
|
|
705
|
+
let maintMutated = 0;
|
|
706
|
+
let maintExitReason = 'complete';
|
|
707
|
+
const maxConvs = this.config.maxActiveConversations ?? 5;
|
|
708
|
+
const cooldownMs = this.config.recentConversationCooldownMs ?? 30000;
|
|
709
|
+
const maxCandidates = this.config.maxCandidatesPerPass ?? 200;
|
|
710
|
+
const now = Date.now();
|
|
689
711
|
for (const agentId of agents) {
|
|
690
712
|
const messageDb = this.getMessageDb(agentId);
|
|
691
713
|
if (!messageDb)
|
|
692
714
|
continue;
|
|
693
|
-
// Get active conversations for this agent
|
|
694
715
|
let convRows;
|
|
695
716
|
try {
|
|
696
|
-
convRows = messageDb.prepare(`SELECT id FROM conversations WHERE agent_id = ? AND status = 'active' ORDER BY updated_at DESC LIMIT
|
|
717
|
+
convRows = messageDb.prepare(`SELECT id FROM conversations WHERE agent_id = ? AND status = 'active' ORDER BY updated_at DESC LIMIT ?`).all(agentId, maxConvs);
|
|
697
718
|
}
|
|
698
719
|
catch {
|
|
699
720
|
continue;
|
|
700
721
|
}
|
|
722
|
+
if (convRows.length === 0) {
|
|
723
|
+
if (maintExitReason === 'complete')
|
|
724
|
+
maintExitReason = 'no-conversations';
|
|
725
|
+
continue;
|
|
726
|
+
}
|
|
701
727
|
for (const conv of convRows) {
|
|
702
|
-
|
|
703
|
-
const
|
|
704
|
-
|
|
705
|
-
|
|
728
|
+
maintConsidered++;
|
|
729
|
+
const lastProcessed = this._conversationLastProcessed.get(conv.id) ?? 0;
|
|
730
|
+
if (now - lastProcessed < cooldownMs) {
|
|
731
|
+
maintSkipped++;
|
|
732
|
+
continue;
|
|
733
|
+
}
|
|
734
|
+
maintScanned++;
|
|
735
|
+
// Any successful scan means we're in a real working state —
|
|
736
|
+
// clear any stale 'no-conversations' marker from an earlier agent.
|
|
737
|
+
if (maintExitReason === 'no-conversations')
|
|
738
|
+
maintExitReason = 'complete';
|
|
739
|
+
const noiseSweepResult = runNoiseSweep(messageDb, conv.id, 20, maxCandidates);
|
|
740
|
+
const toolDecayResult = runToolDecay(messageDb, conv.id, 40, maxCandidates);
|
|
741
|
+
const changed = noiseSweepResult.messagesDeleted + toolDecayResult.messagesUpdated;
|
|
742
|
+
if (changed > 0) {
|
|
743
|
+
maintMutated += changed;
|
|
706
744
|
console.log(`[indexer] Proactive pass (conv ${conv.id}): swept ${noiseSweepResult.messagesDeleted} noise msgs, ` +
|
|
707
745
|
`decayed ${toolDecayResult.messagesUpdated} tool results (${toolDecayResult.bytesFreed} bytes freed)`);
|
|
708
746
|
}
|
|
747
|
+
this._conversationLastProcessed.set(conv.id, now);
|
|
748
|
+
if (maintMutated >= maxCandidates) {
|
|
749
|
+
maintExitReason = 'cap-reached';
|
|
750
|
+
break;
|
|
751
|
+
}
|
|
709
752
|
}
|
|
753
|
+
if (maintExitReason === 'cap-reached')
|
|
754
|
+
break;
|
|
755
|
+
}
|
|
756
|
+
this.lastMaintenanceDiagnostics = {
|
|
757
|
+
considered: maintConsidered,
|
|
758
|
+
skipped: maintSkipped,
|
|
759
|
+
scanned: maintScanned,
|
|
760
|
+
mutated: maintMutated,
|
|
761
|
+
durationMs: Date.now() - maintStart,
|
|
762
|
+
exitReason: maintExitReason,
|
|
763
|
+
};
|
|
764
|
+
if (maintScanned > 0) {
|
|
765
|
+
console.log(`[indexer] Maintenance: considered=${maintConsidered} skipped=${maintSkipped} scanned=${maintScanned} mutated=${maintMutated} ` +
|
|
766
|
+
`duration=${this.lastMaintenanceDiagnostics.durationMs}ms exit=${maintExitReason}`);
|
|
710
767
|
}
|
|
711
768
|
// If we reach here, the tick completed without throwing.
|
|
712
769
|
tickSucceeded = true;
|
|
@@ -758,6 +815,9 @@ export class BackgroundIndexer {
|
|
|
758
815
|
knowledgeUpserted: 0,
|
|
759
816
|
tombstoned,
|
|
760
817
|
postCursorMessages: 0,
|
|
818
|
+
contradictionAuditsLogged: 0,
|
|
819
|
+
contradictionsAutoSuperseded: 0,
|
|
820
|
+
contradictionsAutoInvalidated: 0,
|
|
761
821
|
elapsedMs: Date.now() - start,
|
|
762
822
|
};
|
|
763
823
|
}
|
|
@@ -791,7 +851,16 @@ export class BackgroundIndexer {
|
|
|
791
851
|
let topicsUpdated = 0;
|
|
792
852
|
let knowledgeUpserted = 0;
|
|
793
853
|
let supersededFacts = 0;
|
|
854
|
+
let contradictionAuditsLogged = 0;
|
|
855
|
+
let contradictionsAutoSuperseded = 0;
|
|
856
|
+
let contradictionsAutoInvalidated = 0;
|
|
794
857
|
let maxMessageId = lastProcessedId;
|
|
858
|
+
const contradictionDetector = new ContradictionDetector(factStore, this.vectorStore ?? undefined, {
|
|
859
|
+
autoResolve: false,
|
|
860
|
+
maxCandidates: 6,
|
|
861
|
+
minSimilarity: 0.45,
|
|
862
|
+
});
|
|
863
|
+
const contradictionAuditStore = new ContradictionAuditStore(libraryDb);
|
|
795
864
|
for (const msg of ordered) {
|
|
796
865
|
const content = msg.textContent || '';
|
|
797
866
|
if (msg.id > maxMessageId)
|
|
@@ -803,15 +872,50 @@ export class BackgroundIndexer {
|
|
|
803
872
|
const factCandidates = extractFactCandidates(content);
|
|
804
873
|
for (const { content: factContent, confidence: factConfidence } of factCandidates) {
|
|
805
874
|
try {
|
|
875
|
+
const factDomain = domainForAgent(agentId);
|
|
876
|
+
// 1. Detect contradictions BEFORE addFact (operates on existing facts only)
|
|
877
|
+
const contradictionResult = await contradictionDetector.detectOnIngest(agentId, {
|
|
878
|
+
content: factContent,
|
|
879
|
+
domain: factDomain,
|
|
880
|
+
});
|
|
881
|
+
const topContradictions = contradictionResult.contradictions.slice(0, 3);
|
|
882
|
+
// 2. addFact first — we need fact.id for supersede linkage
|
|
806
883
|
const fact = factStore.addFact(agentId, factContent, {
|
|
807
884
|
scope: 'agent',
|
|
808
|
-
domain:
|
|
885
|
+
domain: factDomain,
|
|
809
886
|
confidence: factConfidence,
|
|
810
887
|
sourceType: 'indexer',
|
|
811
888
|
sourceSessionKey: this.getSessionKeyForMessage(messageDb, msg.conversationId),
|
|
812
889
|
sourceRef: `msg:${msg.id}`,
|
|
813
890
|
});
|
|
814
891
|
factsExtracted++;
|
|
892
|
+
// 3. Apply contradiction policy for each candidate (now we have fact.id)
|
|
893
|
+
for (const candidate of topContradictions) {
|
|
894
|
+
const score = candidate.contradictionScore;
|
|
895
|
+
let auditStatus = 'pending';
|
|
896
|
+
if (score >= this.contradictionPolicy.autoSupersedeThreshold) {
|
|
897
|
+
const didSupersede = factStore.markSuperseded(candidate.existingFactId, fact.id);
|
|
898
|
+
if (didSupersede) {
|
|
899
|
+
contradictionsAutoSuperseded++;
|
|
900
|
+
// Immediately remove stale vector so it cannot surface in KNN recall
|
|
901
|
+
if (this.vectorStore) {
|
|
902
|
+
this.vectorStore.removeItem('facts', candidate.existingFactId);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
auditStatus = 'auto-superseded';
|
|
906
|
+
}
|
|
907
|
+
else if (score >= this.contradictionPolicy.autoInvalidateThreshold) {
|
|
908
|
+
const didInvalidate = factStore.invalidateFact(candidate.existingFactId);
|
|
909
|
+
if (didInvalidate) {
|
|
910
|
+
contradictionsAutoInvalidated++;
|
|
911
|
+
}
|
|
912
|
+
auditStatus = 'auto-invalidated';
|
|
913
|
+
}
|
|
914
|
+
if (this.contradictionPolicy.alwaysAudit || auditStatus === 'pending') {
|
|
915
|
+
contradictionAuditStore.recordFactAudit(agentId, { content: factContent, domain: factDomain }, candidate, { sourceRef: `msg:${msg.id}`, status: auditStatus });
|
|
916
|
+
contradictionAuditsLogged++;
|
|
917
|
+
}
|
|
918
|
+
}
|
|
815
919
|
// ── Supersedes detection ─────────────────────────────────
|
|
816
920
|
// Check if the newly extracted fact supersedes an existing one.
|
|
817
921
|
// A supersede is detected when an existing active fact shares the
|
|
@@ -868,17 +972,18 @@ export class BackgroundIndexer {
|
|
|
868
972
|
}
|
|
869
973
|
// 3. Detect and update topics
|
|
870
974
|
const topicName = detectTopic(content);
|
|
871
|
-
if (topicName) {
|
|
975
|
+
if (topicName && topicName.trim().length >= 3) {
|
|
872
976
|
try {
|
|
873
|
-
const
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
977
|
+
const msgSessionKey = this.getSessionKeyForMessage(messageDb, msg.conversationId) || '';
|
|
978
|
+
// findOrCreate handles case-insensitive dedup at the schema level;
|
|
979
|
+
// always touch afterward so message_count reflects real activity
|
|
980
|
+
// rather than sitting at 0 forever (which made every topic an orphan).
|
|
981
|
+
const topic = topicStore.findOrCreate(agentId, topicName, `Auto-detected from conversation`);
|
|
982
|
+
topicStore.touch(topic.id, msgSessionKey, 1);
|
|
983
|
+
topicsUpdated++;
|
|
879
984
|
}
|
|
880
985
|
catch {
|
|
881
|
-
// Skip topic creation errors
|
|
986
|
+
// Skip topic creation/touch errors
|
|
882
987
|
}
|
|
883
988
|
}
|
|
884
989
|
// 4. Extract knowledge candidates
|
|
@@ -912,6 +1017,9 @@ export class BackgroundIndexer {
|
|
|
912
1017
|
topicsUpdated,
|
|
913
1018
|
knowledgeUpserted,
|
|
914
1019
|
tombstoned,
|
|
1020
|
+
contradictionAuditsLogged,
|
|
1021
|
+
contradictionsAutoSuperseded,
|
|
1022
|
+
contradictionsAutoInvalidated,
|
|
915
1023
|
postCursorMessages: postCursor.length,
|
|
916
1024
|
elapsedMs: Date.now() - start,
|
|
917
1025
|
};
|
|
@@ -1146,8 +1254,8 @@ export class BackgroundIndexer {
|
|
|
1146
1254
|
* Create and start a background indexer connected to hypermem databases.
|
|
1147
1255
|
* Used by the hook or a standalone daemon.
|
|
1148
1256
|
*/
|
|
1149
|
-
export function createIndexer(getMessageDb, getLibraryDb, listAgents, config, getCursor, vectorStore, dreamerConfig) {
|
|
1150
|
-
const indexer = new BackgroundIndexer(config, getMessageDb, getLibraryDb, listAgents, getCursor, dreamerConfig);
|
|
1257
|
+
export function createIndexer(getMessageDb, getLibraryDb, listAgents, config, getCursor, vectorStore, dreamerConfig, globalWritePolicy) {
|
|
1258
|
+
const indexer = new BackgroundIndexer(config, getMessageDb, getLibraryDb, listAgents, getCursor, dreamerConfig, globalWritePolicy);
|
|
1151
1259
|
if (vectorStore)
|
|
1152
1260
|
indexer.setVectorStore(vectorStore);
|
|
1153
1261
|
return indexer;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical budget policy for history-window trim and steady-state gradient caps.
|
|
3
|
+
*
|
|
4
|
+
* Phase C C0.1 centralizes these values so compose, afterTurn refresh, plugin
|
|
5
|
+
* trim guards, and regression tests all consume the same source of truth.
|
|
6
|
+
*/
|
|
7
|
+
export declare const TRIM_SOFT_TARGET = 0.65;
|
|
8
|
+
export declare const TRIM_GROWTH_THRESHOLD = 0.05;
|
|
9
|
+
export declare const TRIM_HEADROOM_FRACTION = 0.1;
|
|
10
|
+
export interface TrimBudgetPolicy {
|
|
11
|
+
trimSoftTarget: number;
|
|
12
|
+
trimGrowthThreshold: number;
|
|
13
|
+
trimHeadroomFraction: number;
|
|
14
|
+
}
|
|
15
|
+
export interface ResolvedTrimBudgets extends TrimBudgetPolicy {
|
|
16
|
+
softBudget: number;
|
|
17
|
+
triggerBudget: number;
|
|
18
|
+
targetBudget: number;
|
|
19
|
+
}
|
|
20
|
+
export declare const TRIM_BUDGET_POLICY: TrimBudgetPolicy;
|
|
21
|
+
export declare function resolveTrimBudgets(effectiveBudget: number): ResolvedTrimBudgets;
|
|
22
|
+
//# sourceMappingURL=budget-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"budget-policy.d.ts","sourceRoot":"","sources":["../src/budget-policy.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,gBAAgB,OAAO,CAAC;AACrC,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAC1C,eAAO,MAAM,sBAAsB,MAAO,CAAC;AAE3C,MAAM,WAAW,gBAAgB;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,mBAAoB,SAAQ,gBAAgB;IAC3D,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,kBAAkB,EAAE,gBAI/B,CAAC;AAEH,wBAAgB,kBAAkB,CAAC,eAAe,EAAE,MAAM,GAAG,mBAAmB,CAW/E"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical budget policy for history-window trim and steady-state gradient caps.
|
|
3
|
+
*
|
|
4
|
+
* Phase C C0.1 centralizes these values so compose, afterTurn refresh, plugin
|
|
5
|
+
* trim guards, and regression tests all consume the same source of truth.
|
|
6
|
+
*/
|
|
7
|
+
export const TRIM_SOFT_TARGET = 0.65;
|
|
8
|
+
export const TRIM_GROWTH_THRESHOLD = 0.05;
|
|
9
|
+
export const TRIM_HEADROOM_FRACTION = 0.10;
|
|
10
|
+
export const TRIM_BUDGET_POLICY = Object.freeze({
|
|
11
|
+
trimSoftTarget: TRIM_SOFT_TARGET,
|
|
12
|
+
trimGrowthThreshold: TRIM_GROWTH_THRESHOLD,
|
|
13
|
+
trimHeadroomFraction: TRIM_HEADROOM_FRACTION,
|
|
14
|
+
});
|
|
15
|
+
export function resolveTrimBudgets(effectiveBudget) {
|
|
16
|
+
const safeBudget = Math.max(0, Math.floor(effectiveBudget || 0));
|
|
17
|
+
const softBudget = Math.floor(safeBudget * TRIM_SOFT_TARGET);
|
|
18
|
+
const triggerBudget = Math.floor(softBudget * (1 + TRIM_GROWTH_THRESHOLD));
|
|
19
|
+
const targetBudget = Math.floor(softBudget * (1 - TRIM_HEADROOM_FRACTION));
|
|
20
|
+
return {
|
|
21
|
+
...TRIM_BUDGET_POLICY,
|
|
22
|
+
softBudget,
|
|
23
|
+
triggerBudget,
|
|
24
|
+
targetBudget,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=budget-policy.js.map
|
package/dist/cache.d.ts
CHANGED
|
@@ -19,6 +19,17 @@ export interface WindowCacheMeta {
|
|
|
19
19
|
warnings: string[];
|
|
20
20
|
diagnostics: ComposeDiagnostics;
|
|
21
21
|
composedAt: string;
|
|
22
|
+
/**
|
|
23
|
+
* Deterministic SHA-256 hash of the stable cacheable prefix at compose time.
|
|
24
|
+
* Stored so the C4 fast-exit can detect stable-prefix mutations even when
|
|
25
|
+
* the cursor (message id) has not advanced (e.g. system prompt / identity changed).
|
|
26
|
+
*/
|
|
27
|
+
prefixHash?: string;
|
|
28
|
+
/**
|
|
29
|
+
* SHA-256 hash of the system + identity slot contents that fed the stable prefix.
|
|
30
|
+
* Used by C4 to cheaply detect slot mutations without re-running full compose.
|
|
31
|
+
*/
|
|
32
|
+
prefixInputHash?: string;
|
|
22
33
|
}
|
|
23
34
|
export declare class CacheLayer {
|
|
24
35
|
private db;
|
package/dist/cache.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAiB,MAAM,aAAa,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE7H,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,WAAW,EAAE,kBAAkB,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* compositor-utils.ts — Utility functions for context window composition.
|
|
3
|
+
*
|
|
4
|
+
* Provides ordering strategies that improve LLM attention over retrieved
|
|
5
|
+
* documents placed into a prompt.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Reorder documents using zigzag placement to mitigate
|
|
9
|
+
* "Lost in the Middle" attention degradation in LLMs.
|
|
10
|
+
*
|
|
11
|
+
* LLMs exhibit a U-shaped attention curve: items at the beginning and end
|
|
12
|
+
* of context receive ~30% more attention than items in the middle.
|
|
13
|
+
* This function places the most relevant items at the edges and the least
|
|
14
|
+
* relevant items near the center, maximising effective attention on the
|
|
15
|
+
* information that matters most.
|
|
16
|
+
*
|
|
17
|
+
* Reference: Liu et al., "Lost in the Middle: How Language Models Use Long
|
|
18
|
+
* Contexts", ICLR 2025. https://arxiv.org/abs/2307.03172
|
|
19
|
+
*
|
|
20
|
+
* Input: [d1, d2, d3, d4, d5] (sorted by relevance, descending)
|
|
21
|
+
* Output: [d1, d3, d5, d4, d2] (most relevant at edges, least in middle)
|
|
22
|
+
*
|
|
23
|
+
* Algorithm:
|
|
24
|
+
* - Items at even positions in the input (0, 2, 4, …) fill from the front.
|
|
25
|
+
* - Items at odd positions in the input (1, 3, 5, …) fill from the back.
|
|
26
|
+
*
|
|
27
|
+
* @param docs - Array sorted by relevance (most relevant first).
|
|
28
|
+
* @returns A new array reordered so the most relevant items sit at the edges.
|
|
29
|
+
*/
|
|
30
|
+
export declare function zigzagOrder<T>(docs: T[]): T[];
|
|
31
|
+
//# sourceMappingURL=compositor-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compositor-utils.d.ts","sourceRoot":"","sources":["../src/compositor-utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CAkB7C"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* compositor-utils.ts — Utility functions for context window composition.
|
|
3
|
+
*
|
|
4
|
+
* Provides ordering strategies that improve LLM attention over retrieved
|
|
5
|
+
* documents placed into a prompt.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Reorder documents using zigzag placement to mitigate
|
|
9
|
+
* "Lost in the Middle" attention degradation in LLMs.
|
|
10
|
+
*
|
|
11
|
+
* LLMs exhibit a U-shaped attention curve: items at the beginning and end
|
|
12
|
+
* of context receive ~30% more attention than items in the middle.
|
|
13
|
+
* This function places the most relevant items at the edges and the least
|
|
14
|
+
* relevant items near the center, maximising effective attention on the
|
|
15
|
+
* information that matters most.
|
|
16
|
+
*
|
|
17
|
+
* Reference: Liu et al., "Lost in the Middle: How Language Models Use Long
|
|
18
|
+
* Contexts", ICLR 2025. https://arxiv.org/abs/2307.03172
|
|
19
|
+
*
|
|
20
|
+
* Input: [d1, d2, d3, d4, d5] (sorted by relevance, descending)
|
|
21
|
+
* Output: [d1, d3, d5, d4, d2] (most relevant at edges, least in middle)
|
|
22
|
+
*
|
|
23
|
+
* Algorithm:
|
|
24
|
+
* - Items at even positions in the input (0, 2, 4, …) fill from the front.
|
|
25
|
+
* - Items at odd positions in the input (1, 3, 5, …) fill from the back.
|
|
26
|
+
*
|
|
27
|
+
* @param docs - Array sorted by relevance (most relevant first).
|
|
28
|
+
* @returns A new array reordered so the most relevant items sit at the edges.
|
|
29
|
+
*/
|
|
30
|
+
export function zigzagOrder(docs) {
|
|
31
|
+
if (docs.length <= 2) {
|
|
32
|
+
return docs.slice();
|
|
33
|
+
}
|
|
34
|
+
const result = new Array(docs.length);
|
|
35
|
+
let front = 0;
|
|
36
|
+
let back = docs.length - 1;
|
|
37
|
+
for (let i = 0; i < docs.length; i++) {
|
|
38
|
+
if (i % 2 === 0) {
|
|
39
|
+
result[front++] = docs[i];
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
result[back--] = docs[i];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=compositor-utils.js.map
|