@psiclawops/hypermem 0.7.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +30 -38
- package/README.md +83 -35
- package/dist/background-indexer.d.ts +14 -3
- package/dist/background-indexer.d.ts.map +1 -1
- package/dist/background-indexer.js +126 -18
- 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/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 +38 -0
- package/dist/dreaming-promoter.d.ts.map +1 -1
- package/dist/dreaming-promoter.js +68 -2
- package/dist/index.d.ts +68 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +402 -26
- 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/open-domain.js +1 -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/session-flusher.d.ts +2 -2
- package/dist/session-flusher.d.ts.map +1 -1
- package/dist/session-flusher.js +1 -1
- package/dist/temporal-store.js +2 -2
- 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/types.d.ts +233 -1
- 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.
|
|
@@ -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
|
package/dist/compositor.d.ts
CHANGED
|
@@ -17,12 +17,80 @@ import { CacheLayer } from './cache.js';
|
|
|
17
17
|
type AnyCache = CacheLayer;
|
|
18
18
|
import { VectorStore } from './vector-store.js';
|
|
19
19
|
import { type OrgRegistry } from './cross-agent.js';
|
|
20
|
+
import { type DegradationReason } from './degradation.js';
|
|
20
21
|
/**
|
|
21
22
|
* Files that OpenClaw's contextInjection injects into the system prompt.
|
|
22
23
|
* HyperMem must not re-inject these via doc chunk retrieval to avoid duplication.
|
|
23
24
|
* Exported so plugin and other consumers can share the same dedup set.
|
|
24
25
|
*/
|
|
25
26
|
export declare const OPENCLAW_BOOTSTRAP_FILES: Set<string>;
|
|
27
|
+
/**
|
|
28
|
+
* B4: Compute model-aware lane budget fractions.
|
|
29
|
+
*
|
|
30
|
+
* Resolves the effective historyFraction and memoryFraction for a compose pass
|
|
31
|
+
* given the model and its effective budget. Uses the MECW catalog to blend
|
|
32
|
+
* away from fixed fractions when the budget approaches the MECW ceiling,
|
|
33
|
+
* so the compositor allocates proportionally for what the model can actually use.
|
|
34
|
+
*
|
|
35
|
+
* Returns:
|
|
36
|
+
* historyFraction — fraction of effective budget to give history
|
|
37
|
+
* memoryFraction — fraction of effective budget to give memory pool
|
|
38
|
+
* mecwProfile — which MECW entry matched (undefined = no match / full window)
|
|
39
|
+
* mecwApplied — true when MECW adjustment changed the fractions
|
|
40
|
+
* mecwBlend — 0..1 blend factor (0 = below floor, 1 = at/above ceiling)
|
|
41
|
+
*/
|
|
42
|
+
export declare function resolveModelLaneBudgets(model: string | undefined, effectiveBudget: number, configHistoryFraction: number, configMemoryFraction: number): {
|
|
43
|
+
historyFraction: number;
|
|
44
|
+
memoryFraction: number;
|
|
45
|
+
mecwProfile: string | undefined;
|
|
46
|
+
mecwApplied: boolean;
|
|
47
|
+
mecwBlend: number;
|
|
48
|
+
};
|
|
49
|
+
/** Session classification labels — used for adaptive depth selection. */
|
|
50
|
+
export type SessionType = 'plain-chat' | 'tool-heavy';
|
|
51
|
+
/**
|
|
52
|
+
* Classify a session based on the ratio of tool messages in the recent sample.
|
|
53
|
+
* 'tool-heavy': >= 20% of sampled messages carry tool calls or tool results.
|
|
54
|
+
* 'plain-chat': below that threshold (text-only or occasional tool use).
|
|
55
|
+
*
|
|
56
|
+
* The 20% threshold is intentionally conservative: most tool-heavy agents
|
|
57
|
+
* have tool messages on every assistant turn, so the ratio quickly exceeds
|
|
58
|
+
* the threshold without false-positive risk for light tool users.
|
|
59
|
+
*/
|
|
60
|
+
export declare function classifySessionType(messages: NeutralMessage[]): SessionType;
|
|
61
|
+
/**
|
|
62
|
+
* Estimate the average token cost per message from a recent message sample.
|
|
63
|
+
* Uses the same estimateMessageTokens heuristic as the compositor budget walk
|
|
64
|
+
* so the returned depth is directly comparable to the historyFillCap check.
|
|
65
|
+
*
|
|
66
|
+
* Returns a conservative floor (100 tokens) when the sample is empty to avoid
|
|
67
|
+
* returning Infinity when historyBudget is divided by density.
|
|
68
|
+
*/
|
|
69
|
+
export declare function estimateObservedMsgDensity(messages: NeutralMessage[]): number;
|
|
70
|
+
/**
|
|
71
|
+
* Compute an adaptive history depth that pre-fits the session type.
|
|
72
|
+
*
|
|
73
|
+
* For plain-chat sessions: divides historyBudget by observed density to get a
|
|
74
|
+
* depth that fills the budget without overflow, bounded by the default maximum.
|
|
75
|
+
* Recall quality is preserved because the density estimate is honest for
|
|
76
|
+
* text-only turns.
|
|
77
|
+
*
|
|
78
|
+
* For tool-heavy sessions: applies a post-gradient compression factor
|
|
79
|
+
* (TOOL_GRADIENT_DENSITY_FACTOR = 0.30) to the observed pre-gradient density.
|
|
80
|
+
* This accounts for the gradient transform collapsing large tool payloads to
|
|
81
|
+
* prose stubs before the budget-fit walk runs. A tighter depth is chosen so
|
|
82
|
+
* the gradient-compressed messages fit inside historyFillCap without triggering
|
|
83
|
+
* a rescue trim.
|
|
84
|
+
*
|
|
85
|
+
* A 0.85 safety margin is applied to both paths so estimates that are
|
|
86
|
+
* slightly off don't cause immediate overflow on the first warm compose.
|
|
87
|
+
*
|
|
88
|
+
* Min/max bounds ensure the compositor always sees a meaningful window:
|
|
89
|
+
* - plain-chat min: 20 messages (enough for short recent context)
|
|
90
|
+
* - tool-heavy min: 15 messages (recent tool context + a few prior turns)
|
|
91
|
+
* - shared max: config.maxHistoryMessages (never exceed the DB fetch ceiling)
|
|
92
|
+
*/
|
|
93
|
+
export declare function computeAdaptiveHistoryDepth(sessionType: SessionType, observedDensity: number, historyBudgetTokens: number, maxHistoryMessages: number): number;
|
|
26
94
|
export { CollectionTrigger, DEFAULT_TRIGGERS, matchTriggers } from './trigger-registry.js';
|
|
27
95
|
export { getTurnAge, applyToolGradient, appendToolSummary, truncateWithHeadTail, applyTierPayloadCap, evictLargeToolResults };
|
|
28
96
|
/**
|
|
@@ -55,6 +123,78 @@ declare function applyTierPayloadCap(msg: NeutralMessage, perResultCap: number,
|
|
|
55
123
|
usedChars: number;
|
|
56
124
|
};
|
|
57
125
|
declare function evictLargeToolResults<T extends NeutralMessage>(messages: T[]): T[];
|
|
126
|
+
export declare function resolveArtifactOversizeThreshold(effectiveBudget: number): number;
|
|
127
|
+
/**
|
|
128
|
+
* C2: Degrade an oversized doc chunk to a canonical ArtifactRef string.
|
|
129
|
+
*
|
|
130
|
+
* When a retrieved chunk's content exceeds the oversize threshold (in tokens),
|
|
131
|
+
* replace it with a fetchable canonical reference instead of injecting raw content.
|
|
132
|
+
* This preserves headroom in the lane instead of filling it with a large payload.
|
|
133
|
+
*
|
|
134
|
+
* Returns:
|
|
135
|
+
* - `null` → content is within the threshold; caller should inject as-is.
|
|
136
|
+
* - `string` → canonical artifact reference; caller should inject this instead of raw content.
|
|
137
|
+
*
|
|
138
|
+
* The sizeTokens reported in the reference is the ACTUAL estimated size so downstream
|
|
139
|
+
* tooling can make informed decisions about whether to fetch.
|
|
140
|
+
*/
|
|
141
|
+
export declare function degradeOversizedDocChunk(chunkId: string, sourcePath: string, content: string, thresholdTokens: number): string | null;
|
|
142
|
+
/**
|
|
143
|
+
* C2: Resolve oversized artifacts in a history message array.
|
|
144
|
+
*
|
|
145
|
+
* Scans the message array and replaces user/assistant messages whose text content
|
|
146
|
+
* exceeds the model-aware artifact oversize threshold with canonical ArtifactRef
|
|
147
|
+
* strings. System messages, tool-call messages, and tool-result messages are always
|
|
148
|
+
* passed through unchanged.
|
|
149
|
+
*
|
|
150
|
+
* @param messages — neutral message array (already-assembled history window)
|
|
151
|
+
* @param effectiveBudget — effective model budget from B4 (drives the threshold)
|
|
152
|
+
* @returns { messages, refCount, tokensSaved }
|
|
153
|
+
*/
|
|
154
|
+
export declare function resolveOversizedArtifacts<T extends NeutralMessage>(messages: T[], effectiveBudget: number): {
|
|
155
|
+
messages: T[];
|
|
156
|
+
refCount: number;
|
|
157
|
+
tokensSaved: number;
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* Result of a single tool-chain ejection pass.
|
|
161
|
+
* Returned by resolveToolChainEjections so callers can accumulate telemetry.
|
|
162
|
+
*/
|
|
163
|
+
export interface ToolChainEjectionResult<T extends NeutralMessage> {
|
|
164
|
+
/** The transformed message array (may contain stubs in place of results). */
|
|
165
|
+
messages: T[];
|
|
166
|
+
/** Number of tool-result messages fully co-ejected (removed from the array). */
|
|
167
|
+
coEjections: number;
|
|
168
|
+
/** Number of tool-result payloads replaced with a canonical stub string. */
|
|
169
|
+
stubReplacements: number;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* C1: Centralized tool-chain dependency ejection.
|
|
173
|
+
*
|
|
174
|
+
* Given a set of tool-use message indices that are being ejected from the
|
|
175
|
+
* context window, this function ensures that no orphaned tool-results survive:
|
|
176
|
+
*
|
|
177
|
+
* - For each ejected assistant message carrying toolCalls, collect the set
|
|
178
|
+
* of call IDs being removed.
|
|
179
|
+
* - Walk the remaining messages: if a message's toolResults reference any
|
|
180
|
+
* of those ejected IDs:
|
|
181
|
+
* a) If the message carries ONLY tool-results and no other text, co-eject
|
|
182
|
+
* it (remove it entirely). This is the zero-cost path.
|
|
183
|
+
* b) If the message also carries text content, replace only the dependent
|
|
184
|
+
* toolResults entries with canonical ToolChainStub strings so the
|
|
185
|
+
* message is not silently mutilated.
|
|
186
|
+
*
|
|
187
|
+
* The caller is responsible for removing the ejected messages by index BEFORE
|
|
188
|
+
* or AFTER calling this function; this function operates on the full array and
|
|
189
|
+
* marks the ejected indices for removal, returning the cleaned result.
|
|
190
|
+
*
|
|
191
|
+
* @param messages Full message array (order preserved)
|
|
192
|
+
* @param ejectIndices Set of indices into `messages` that are being ejected
|
|
193
|
+
* (these are the tool-use / assistant messages being removed).
|
|
194
|
+
* @param reason DegradationReason to embed in any canonical stubs.
|
|
195
|
+
* @returns Cleaned message array + telemetry counters.
|
|
196
|
+
*/
|
|
197
|
+
export declare function resolveToolChainEjections<T extends NeutralMessage>(messages: T[], ejectIndices: Set<number>, reason?: DegradationReason): ToolChainEjectionResult<T>;
|
|
58
198
|
/**
|
|
59
199
|
* Apply gradient tool treatment to a message array.
|
|
60
200
|
*
|
|
@@ -96,6 +236,27 @@ export declare class Compositor {
|
|
|
96
236
|
* Return the currently cached org registry.
|
|
97
237
|
*/
|
|
98
238
|
get orgRegistry(): OrgRegistry;
|
|
239
|
+
/**
|
|
240
|
+
* Sprint 2.1: Hydrate tool-artifact stubs in the active turn.
|
|
241
|
+
*
|
|
242
|
+
* The active turn is the contiguous trailing block of tool-bearing messages
|
|
243
|
+
* at the tail of the assembled window (positional, NOT turn_id-based):
|
|
244
|
+
* - Walk backward from the last message
|
|
245
|
+
* - Collect tool-bearing messages (toolCalls != null OR toolResults != null)
|
|
246
|
+
* - Plus the bounding user message that opened the turn
|
|
247
|
+
* - Stop at the first plain message once at least one tool message was found
|
|
248
|
+
*
|
|
249
|
+
* For every toolResult stub with an `artifact=<id>` pointer, look up the
|
|
250
|
+
* full payload in ToolArtifactStore and replace the stub content in-place.
|
|
251
|
+
* Uses a single batched `WHERE id IN (...)` lookup (no N+1 queries).
|
|
252
|
+
* Touches `last_used_at` on every hydrated artifact in a single batch.
|
|
253
|
+
*
|
|
254
|
+
* Failure mode: if a lookup returns null (artifact missing), leave the stub
|
|
255
|
+
* unchanged and increment hydrationMisses.
|
|
256
|
+
*
|
|
257
|
+
* Returns diagnostics counters.
|
|
258
|
+
*/
|
|
259
|
+
private hydrateActiveTurnArtifacts;
|
|
99
260
|
/**
|
|
100
261
|
* Compose a complete message array for sending to an LLM.
|
|
101
262
|
*
|
|
@@ -122,7 +283,7 @@ export declare class Compositor {
|
|
|
122
283
|
/** Model string for budget resolution. If omitted, falls back to defaultTokenBudget. */
|
|
123
284
|
model?: string;
|
|
124
285
|
}): Promise<void>;
|
|
125
|
-
refreshRedisGradient(agentId: string, sessionKey: string, db: DatabaseSync, tokenBudget?: number): Promise<void>;
|
|
286
|
+
refreshRedisGradient(agentId: string, sessionKey: string, db: DatabaseSync, tokenBudget?: number, historyDepth?: number): Promise<void>;
|
|
126
287
|
/**
|
|
127
288
|
* Get slot content: try Redis first, fall back to SQLite.
|
|
128
289
|
*/
|
|
@@ -145,6 +306,7 @@ export declare class Compositor {
|
|
|
145
306
|
* Returns [content, factCount, scopeFilteredCount] or null if DB unavailable.
|
|
146
307
|
*/
|
|
147
308
|
private buildFactsFromDb;
|
|
309
|
+
private buildFactSectionsFromDb;
|
|
148
310
|
/**
|
|
149
311
|
* Build knowledge content from library DB.
|
|
150
312
|
* Prioritizes high-confidence, non-superseded entries.
|