claude-memory-layer 1.0.31 → 1.0.33
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/README.md +9 -2
- package/dist/cli/index.js +1110 -72
- package/dist/cli/index.js.map +4 -4
- package/dist/core/index.js +414 -25
- package/dist/core/index.js.map +2 -2
- package/dist/hooks/post-tool-use.js +416 -27
- package/dist/hooks/post-tool-use.js.map +2 -2
- package/dist/hooks/semantic-daemon.js +416 -27
- package/dist/hooks/semantic-daemon.js.map +2 -2
- package/dist/hooks/session-end.js +416 -27
- package/dist/hooks/session-end.js.map +2 -2
- package/dist/hooks/session-start.js +416 -27
- package/dist/hooks/session-start.js.map +2 -2
- package/dist/hooks/stop.js +416 -27
- package/dist/hooks/stop.js.map +2 -2
- package/dist/hooks/user-prompt-submit.js +504 -34
- package/dist/hooks/user-prompt-submit.js.map +2 -2
- package/dist/index.js +416 -27
- package/dist/index.js.map +2 -2
- package/dist/mcp/index.js +407 -32
- package/dist/mcp/index.js.map +2 -2
- package/dist/server/api/index.js +850 -44
- package/dist/server/api/index.js.map +3 -3
- package/dist/server/index.js +1073 -64
- package/dist/server/index.js.map +3 -3
- package/dist/services/memory-service.js +416 -27
- package/dist/services/memory-service.js.map +2 -2
- package/dist/ui/assets/js/bootstrap.js +2 -0
- package/dist/ui/assets/js/overview.js +166 -3
- package/dist/ui/assets/js/state.js +3 -0
- package/dist/ui/index.html +20 -0
- package/dist/ui/style.css +193 -0
- package/package.json +15 -2
- package/scripts/postinstall-embedding-backend.cjs +16 -12
- package/AGENTS.md +0 -71
- package/CLAUDE.md +0 -30
- package/HANDOFF.md +0 -92
- package/Memo.txt +0 -558
- package/benchmarks/replay/anonymized-real-sessions.json +0 -48
- package/config/kpi-thresholds.json +0 -7
- package/context.md +0 -636
- package/docs/ARCHITECTURE_COMPARISON_AND_RECOMMENDATIONS.md +0 -627
- package/docs/HERMES_MEMORY_INGESTION_ANALYSIS.md +0 -440
- package/docs/MCP_MEMORY_SERVICE_COMPARATIVE_REVIEW.md +0 -271
- package/docs/MEMORY_USEFULNESS_AUDIT.md +0 -371
- package/docs/MEMORY_USEFULNESS_AUDIT_RAW.json +0 -80
- package/docs/MEMSEARCH_PROJECT_STRUCTURE_ANALYSIS.md +0 -333
- package/docs/MEMU_ADOPTION.md +0 -40
- package/docs/OPERATIONS.md +0 -18
- package/docs/PRODUCT_VALIDATION_MATRIX.md +0 -82
- package/docs/PROJECT_STRUCTURE_ANALYSIS.md +0 -421
- package/docs/REFACTORING_MILESTONES_AND_ISSUES.md +0 -501
- package/docs/REFACTORING_PLAN_THIN_CORE.md +0 -414
- package/docs/REFERENCE_PROJECT_ANALYSES.md +0 -25
- package/docs/SUPERLOCALMEMORY_PROJECT_STRUCTURE_ANALYSIS.md +0 -452
- package/docs/TARGET_ARCHITECTURE_AND_FOLDER_STRUCTURE.md +0 -446
- package/docs/architecture/comparison-index.md +0 -47
- package/docs/reports/codex-real-data-validation-20260505T040447Z.md +0 -46
- package/plan.md +0 -1642
- package/scripts/build.ts +0 -159
- package/scripts/bump-patch-version.sh +0 -18
- package/scripts/delete-unknown-projects.js +0 -154
- package/scripts/fix-sync-gap.js +0 -32
- package/scripts/generate-session-qrels.ts +0 -126
- package/scripts/heartbeat-memory-orchestrator.sh +0 -28
- package/scripts/replay-retrieval-benchmark.ts +0 -69
- package/scripts/report-sync-gap.js +0 -26
- package/scripts/review-queue-auto-resolve.js +0 -21
- package/scripts/sync-gap-auto-heal.sh +0 -17
- package/spec.md +0 -624
- package/specs/20260207-dashboard-upgrade/context.md +0 -38
- package/specs/20260207-dashboard-upgrade/spec.md +0 -96
- package/specs/citations-system/context.md +0 -243
- package/specs/citations-system/plan.md +0 -495
- package/specs/citations-system/spec.md +0 -371
- package/specs/endless-mode/context.md +0 -305
- package/specs/endless-mode/plan.md +0 -620
- package/specs/endless-mode/spec.md +0 -455
- package/specs/entity-edge-model/context.md +0 -401
- package/specs/entity-edge-model/plan.md +0 -459
- package/specs/entity-edge-model/spec.md +0 -391
- package/specs/evidence-aligner-v2/context.md +0 -401
- package/specs/evidence-aligner-v2/plan.md +0 -303
- package/specs/evidence-aligner-v2/spec.md +0 -312
- package/specs/mcp-desktop-integration/context.md +0 -278
- package/specs/mcp-desktop-integration/plan.md +0 -550
- package/specs/mcp-desktop-integration/spec.md +0 -494
- package/specs/memory-utilization-improvements/context.md +0 -145
- package/specs/memory-utilization-improvements/plan.md +0 -361
- package/specs/memory-utilization-improvements/spec.md +0 -361
- package/specs/post-tool-use-hook/context.md +0 -319
- package/specs/post-tool-use-hook/plan.md +0 -469
- package/specs/post-tool-use-hook/spec.md +0 -364
- package/specs/private-tags/context.md +0 -288
- package/specs/private-tags/plan.md +0 -412
- package/specs/private-tags/spec.md +0 -345
- package/specs/progressive-disclosure/context.md +0 -346
- package/specs/progressive-disclosure/plan.md +0 -663
- package/specs/progressive-disclosure/spec.md +0 -415
- package/specs/selective-tool-observation/context.md +0 -100
- package/specs/selective-tool-observation/plan.md +0 -158
- package/specs/selective-tool-observation/spec.md +0 -127
- package/specs/task-entity-system/context.md +0 -297
- package/specs/task-entity-system/plan.md +0 -301
- package/specs/task-entity-system/spec.md +0 -314
- package/specs/thin-core-refactor/context.md +0 -275
- package/specs/thin-core-refactor/plan.md +0 -536
- package/specs/thin-core-refactor/spec.md +0 -465
- package/specs/vector-outbox-v2/context.md +0 -470
- package/specs/vector-outbox-v2/plan.md +0 -562
- package/specs/vector-outbox-v2/spec.md +0 -466
- package/specs/web-viewer-ui/context.md +0 -384
- package/specs/web-viewer-ui/plan.md +0 -797
- package/specs/web-viewer-ui/spec.md +0 -516
- package/src/adapters/claude/capture/index.ts +0 -3
- package/src/adapters/claude/context/index.ts +0 -3
- package/src/adapters/claude/hooks/index.ts +0 -21
- package/src/adapters/claude/hooks/post-tool-use.ts +0 -239
- package/src/adapters/claude/hooks/prompt-injection-policy.ts +0 -104
- package/src/adapters/claude/hooks/semantic-daemon-client.ts +0 -209
- package/src/adapters/claude/hooks/semantic-daemon.ts +0 -283
- package/src/adapters/claude/hooks/session-end.ts +0 -59
- package/src/adapters/claude/hooks/session-start.ts +0 -73
- package/src/adapters/claude/hooks/stop.ts +0 -128
- package/src/adapters/claude/hooks/user-prompt-submit.ts +0 -361
- package/src/adapters/claude/index.ts +0 -4
- package/src/adapters/claude/transcript/index.ts +0 -4
- package/src/adapters/claude/transcript/transcript-reader.ts +0 -57
- package/src/adapters/claude/transcript/turn-reconstructor.ts +0 -65
- package/src/apps/cli/claude-settings-hooks.ts +0 -138
- package/src/apps/cli/codex-import-runner.ts +0 -125
- package/src/apps/cli/codex-validation-output.ts +0 -95
- package/src/apps/cli/hermes-import-runner.ts +0 -130
- package/src/apps/cli/hermes-validation-output.ts +0 -91
- package/src/apps/cli/index.ts +0 -1735
- package/src/apps/cli/mcp-install.ts +0 -106
- package/src/apps/cli/retrieval-disclosure-output.ts +0 -196
- package/src/apps/dashboard/assets/js/bootstrap.js +0 -244
- package/src/apps/dashboard/assets/js/chat.js +0 -373
- package/src/apps/dashboard/assets/js/disclosure.js +0 -232
- package/src/apps/dashboard/assets/js/modals.js +0 -298
- package/src/apps/dashboard/assets/js/overview.js +0 -655
- package/src/apps/dashboard/assets/js/state.js +0 -72
- package/src/apps/dashboard/assets/js/views.js +0 -468
- package/src/apps/dashboard/index.html +0 -543
- package/src/apps/dashboard/index.ts +0 -3
- package/src/apps/dashboard/style.css +0 -1750
- package/src/apps/index.ts +0 -5
- package/src/apps/server/api/chat.ts +0 -244
- package/src/apps/server/api/citations.ts +0 -105
- package/src/apps/server/api/events.ts +0 -137
- package/src/apps/server/api/health.ts +0 -53
- package/src/apps/server/api/index.ts +0 -26
- package/src/apps/server/api/projects.ts +0 -74
- package/src/apps/server/api/search.ts +0 -184
- package/src/apps/server/api/sessions.ts +0 -115
- package/src/apps/server/api/stats.ts +0 -723
- package/src/apps/server/api/turns.ts +0 -143
- package/src/apps/server/api/utils.ts +0 -65
- package/src/apps/server/index.ts +0 -111
- package/src/cli/index.ts +0 -3
- package/src/cli/retrieval-disclosure-output.ts +0 -2
- package/src/compat/index.ts +0 -5
- package/src/core/canonical-key.ts +0 -186
- package/src/core/citation-generator.ts +0 -63
- package/src/core/consolidated-store.ts +0 -356
- package/src/core/consolidation-worker.ts +0 -493
- package/src/core/context-formatter.ts +0 -276
- package/src/core/continuity-manager.ts +0 -341
- package/src/core/db-wrapper.ts +0 -64
- package/src/core/derive/fact-deriver.ts +0 -170
- package/src/core/derive/index.ts +0 -2
- package/src/core/derive/summary-deriver.ts +0 -76
- package/src/core/edge-repo.ts +0 -333
- package/src/core/embedder.ts +0 -4
- package/src/core/engine/embedding-maintenance-service.ts +0 -187
- package/src/core/engine/endless-memory-services.ts +0 -4
- package/src/core/engine/index.ts +0 -19
- package/src/core/engine/memory-engine-services.ts +0 -170
- package/src/core/engine/memory-ingest-service.ts +0 -317
- package/src/core/engine/memory-query-service.ts +0 -173
- package/src/core/engine/memory-runtime-service.ts +0 -162
- package/src/core/engine/memory-service-composition.ts +0 -231
- package/src/core/engine/retrieval-analytics-service.ts +0 -181
- package/src/core/engine/retrieval-disclosure-service.ts +0 -420
- package/src/core/engine/retrieval-orchestrator.ts +0 -377
- package/src/core/engine/retrieval-services.ts +0 -176
- package/src/core/engine/shared-memory-services.ts +0 -4
- package/src/core/entity-repo.ts +0 -349
- package/src/core/event-store.ts +0 -779
- package/src/core/evidence-aligner.ts +0 -635
- package/src/core/external-market-context.ts +0 -582
- package/src/core/graduation-worker.ts +0 -171
- package/src/core/graduation.ts +0 -377
- package/src/core/index.ts +0 -64
- package/src/core/ingest-interceptor.ts +0 -80
- package/src/core/markdown-mirror.ts +0 -70
- package/src/core/matcher.ts +0 -208
- package/src/core/md-mirror.ts +0 -92
- package/src/core/metadata-extractor.ts +0 -203
- package/src/core/model/memory-fact.ts +0 -30
- package/src/core/model/memory-rule.ts +0 -14
- package/src/core/model/memory-summary.ts +0 -21
- package/src/core/model/raw-event.ts +0 -28
- package/src/core/model/retrieval-result.ts +0 -35
- package/src/core/mongo-sync-config.ts +0 -165
- package/src/core/mongo-sync-worker.ts +0 -381
- package/src/core/privacy/filter.ts +0 -190
- package/src/core/privacy/index.ts +0 -20
- package/src/core/privacy/tag-parser.ts +0 -145
- package/src/core/product-validation-matrix.ts +0 -314
- package/src/core/progressive-retriever.ts +0 -414
- package/src/core/registry/project-path.ts +0 -54
- package/src/core/registry/session-registry.ts +0 -69
- package/src/core/replay-evaluator.ts +0 -625
- package/src/core/retrieval-benchmark.ts +0 -117
- package/src/core/retrieval-quality.ts +0 -109
- package/src/core/retriever.ts +0 -800
- package/src/core/session-qrels.ts +0 -360
- package/src/core/shared-event-store.ts +0 -114
- package/src/core/shared-promoter.ts +0 -249
- package/src/core/shared-store.ts +0 -289
- package/src/core/shared-vector-store.ts +0 -203
- package/src/core/sqlite-event-store.ts +0 -1846
- package/src/core/sqlite-wrapper.ts +0 -116
- package/src/core/sync-worker.ts +0 -228
- package/src/core/tag-taxonomy.ts +0 -51
- package/src/core/task/blocker-resolver.ts +0 -333
- package/src/core/task/index.ts +0 -9
- package/src/core/task/task-matcher.ts +0 -240
- package/src/core/task/task-projector.ts +0 -358
- package/src/core/task/task-resolver.ts +0 -421
- package/src/core/turn-state.ts +0 -207
- package/src/core/types.ts +0 -952
- package/src/core/vector-outbox.ts +0 -299
- package/src/core/vector-store.ts +0 -231
- package/src/core/vector-worker.ts +0 -521
- package/src/core/working-set-store.ts +0 -257
- package/src/extensions/endless-memory/endless-memory-services.ts +0 -350
- package/src/extensions/endless-memory/index.ts +0 -1
- package/src/extensions/index.ts +0 -5
- package/src/extensions/mcp/handlers.ts +0 -960
- package/src/extensions/mcp/index.ts +0 -48
- package/src/extensions/mcp/tools.ts +0 -252
- package/src/extensions/shared-memory/index.ts +0 -1
- package/src/extensions/shared-memory/shared-memory-services.ts +0 -211
- package/src/extensions/vector/embedder.ts +0 -234
- package/src/extensions/vector/index.ts +0 -1
- package/src/hooks/post-tool-use.ts +0 -9
- package/src/hooks/semantic-daemon-client.ts +0 -1
- package/src/hooks/semantic-daemon.ts +0 -11
- package/src/hooks/session-end.ts +0 -9
- package/src/hooks/session-start.ts +0 -9
- package/src/hooks/stop.ts +0 -9
- package/src/hooks/user-prompt-submit.ts +0 -9
- package/src/index.ts +0 -13
- package/src/mcp/handlers.ts +0 -2
- package/src/mcp/index.ts +0 -4
- package/src/mcp/tools.ts +0 -2
- package/src/server/api/chat.ts +0 -2
- package/src/server/api/citations.ts +0 -2
- package/src/server/api/events.ts +0 -2
- package/src/server/api/health.ts +0 -2
- package/src/server/api/index.ts +0 -2
- package/src/server/api/projects.ts +0 -2
- package/src/server/api/search.ts +0 -2
- package/src/server/api/sessions.ts +0 -2
- package/src/server/api/stats.ts +0 -2
- package/src/server/api/turns.ts +0 -2
- package/src/server/api/utils.ts +0 -2
- package/src/server/index.ts +0 -2
- package/src/services/bootstrap-organizer.ts +0 -463
- package/src/services/codex-session-history-importer.ts +0 -966
- package/src/services/hermes-session-history-importer.ts +0 -733
- package/src/services/memory-service-config.ts +0 -36
- package/src/services/memory-service-registry.ts +0 -150
- package/src/services/memory-service.ts +0 -688
- package/src/services/session-history-importer.ts +0 -629
- package/tests/README.md +0 -23
- package/tests/adapters/claude/claude-semantic-daemon-adapter.test.ts +0 -54
- package/tests/adapters/claude/claude-transcript-reconstructor.test.ts +0 -98
- package/tests/adapters/claude-hook-prompt-injection-policy.test.ts +0 -99
- package/tests/apps/app-layer-boundary.test.ts +0 -48
- package/tests/apps/claude-settings-hooks.test.ts +0 -107
- package/tests/apps/cli-disclosure-output.test.ts +0 -212
- package/tests/apps/codex-import-runner.test.ts +0 -99
- package/tests/apps/codex-validation-output.test.ts +0 -100
- package/tests/apps/hermes-import-runner.test.ts +0 -99
- package/tests/apps/mcp-install-command.test.ts +0 -59
- package/tests/apps/package-build-entrypoints.test.ts +0 -30
- package/tests/apps/postinstall-embedding-backend.test.ts +0 -185
- package/tests/apps/search-api-disclosure.test.ts +0 -162
- package/tests/apps/stats-api-lightweight.test.ts +0 -67
- package/tests/apps/ui-disclosure-output.test.ts +0 -140
- package/tests/core/bootstrap-organizer.test.ts +0 -111
- package/tests/core/canonical-key.test.ts +0 -101
- package/tests/core/codex-session-history-importer-validation.test.ts +0 -185
- package/tests/core/consolidation-worker.test.ts +0 -75
- package/tests/core/embedding-maintenance-service.test.ts +0 -282
- package/tests/core/evidence-aligner.test.ts +0 -152
- package/tests/core/external-market-context.test.ts +0 -209
- package/tests/core/fact-deriver.test.ts +0 -79
- package/tests/core/hermes-session-history-importer-validation.test.ts +0 -609
- package/tests/core/ingest-interceptor.test.ts +0 -38
- package/tests/core/markdown-mirror.test.ts +0 -85
- package/tests/core/matcher.test.ts +0 -112
- package/tests/core/md-mirror.test.ts +0 -50
- package/tests/core/memory-engine-services.test.ts +0 -240
- package/tests/core/memory-ingest-service.test.ts +0 -296
- package/tests/core/memory-query-service.test.ts +0 -129
- package/tests/core/memory-runtime-service.test.ts +0 -201
- package/tests/core/memory-service-composition.test.ts +0 -192
- package/tests/core/memory-service-config.test.ts +0 -41
- package/tests/core/memory-service-facade.test.ts +0 -30
- package/tests/core/memory-service-registry.test.ts +0 -206
- package/tests/core/product-validation-matrix.test.ts +0 -61
- package/tests/core/project-registry.test.ts +0 -78
- package/tests/core/replay-evaluator.test.ts +0 -181
- package/tests/core/retrieval-analytics-service.test.ts +0 -210
- package/tests/core/retrieval-benchmark.test.ts +0 -93
- package/tests/core/retrieval-disclosure-service.test.ts +0 -264
- package/tests/core/retrieval-orchestrator.test.ts +0 -403
- package/tests/core/retrieval-quality.test.ts +0 -31
- package/tests/core/retrieval-services.test.ts +0 -185
- package/tests/core/retriever-fallback-chain.test.ts +0 -223
- package/tests/core/retriever-strategy-scope.test.ts +0 -164
- package/tests/core/retriever.memu-adoption.test.ts +0 -122
- package/tests/core/session-history-importer-filter.test.ts +0 -78
- package/tests/core/session-qrels.test.ts +0 -250
- package/tests/core/sqlite-event-store-replication.test.ts +0 -127
- package/tests/core/summary-deriver.test.ts +0 -66
- package/tests/extensions/embedder-warning-suppression.test.ts +0 -84
- package/tests/extensions/endless-memory-extension-boundary.test.ts +0 -17
- package/tests/extensions/endless-memory-services.test.ts +0 -325
- package/tests/extensions/mcp-context-tools.test.ts +0 -905
- package/tests/extensions/mcp-extension-boundary.test.ts +0 -21
- package/tests/extensions/mcp-package-build.test.ts +0 -22
- package/tests/extensions/mcp-project-aware-tools.test.ts +0 -102
- package/tests/extensions/shared-memory-extension-boundary.test.ts +0 -24
- package/tests/extensions/shared-memory-services.test.ts +0 -309
- package/tests/extensions/vector-extension-boundary.test.ts +0 -21
- package/tsconfig.json +0 -24
- package/vitest.config.ts +0 -15
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { ConsolidationWorker } from '../../src/core/consolidation-worker.js';
|
|
4
|
-
import type { EndlessModeConfig, MemoryEvent } from '../../src/core/types.js';
|
|
5
|
-
|
|
6
|
-
function makeEvent(id: string, content: string, hoursAgo = 20): MemoryEvent {
|
|
7
|
-
return {
|
|
8
|
-
id,
|
|
9
|
-
eventType: 'user_prompt',
|
|
10
|
-
sessionId: 's1',
|
|
11
|
-
timestamp: new Date(Date.now() - hoursAgo * 60 * 60 * 1000),
|
|
12
|
-
content,
|
|
13
|
-
canonicalKey: id,
|
|
14
|
-
dedupeKey: id,
|
|
15
|
-
metadata: {},
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
describe('ConsolidationWorker hierarchy automation', () => {
|
|
20
|
-
it('creates consolidated memories, promotes rules, and returns cost-quality report', async () => {
|
|
21
|
-
const events = [
|
|
22
|
-
makeEvent('e1', 'implement auth bug fix and add tests for token refresh'),
|
|
23
|
-
makeEvent('e2', 'fix auth error in middleware and update tests'),
|
|
24
|
-
makeEvent('e3', 'auth feature update with regression test and bug notes'),
|
|
25
|
-
makeEvent('e4', 'implement retry logic for auth and fix issue with token cache'),
|
|
26
|
-
makeEvent('e5', 'add integration test for auth flow and bug reproduction'),
|
|
27
|
-
];
|
|
28
|
-
|
|
29
|
-
const created: Array<{ memoryId: string; summary: string; topics: string[]; sourceEvents: string[]; confidence: number }> = [];
|
|
30
|
-
const rules: Array<{ rule: string; sourceMemoryIds: string[] }> = [];
|
|
31
|
-
|
|
32
|
-
const workingSetStore = {
|
|
33
|
-
async get() {
|
|
34
|
-
return { recentEvents: events, lastActivity: new Date(), continuityScore: 0.8 };
|
|
35
|
-
},
|
|
36
|
-
async prune(_ids: string[]) {
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
const consolidatedStore = {
|
|
42
|
-
async isAlreadyConsolidated() { return false; },
|
|
43
|
-
async create(input: any) {
|
|
44
|
-
const memoryId = `m-${created.length + 1}`;
|
|
45
|
-
created.push({ memoryId, ...input });
|
|
46
|
-
return memoryId;
|
|
47
|
-
},
|
|
48
|
-
async get(memoryId: string) {
|
|
49
|
-
return created.find((m) => m.memoryId === memoryId) || null;
|
|
50
|
-
},
|
|
51
|
-
async hasRuleForSourceMemory() { return false; },
|
|
52
|
-
async createRule(input: any) {
|
|
53
|
-
rules.push({ rule: input.rule, sourceMemoryIds: input.sourceMemoryIds });
|
|
54
|
-
return `r-${rules.length}`;
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const config: EndlessModeConfig = {
|
|
59
|
-
enabled: true,
|
|
60
|
-
workingSet: { maxEvents: 100, timeWindowHours: 24, minRelevanceScore: 0.5 },
|
|
61
|
-
consolidation: { triggerIntervalMs: 3600000, triggerEventCount: 3, triggerIdleMs: 1000, useLLMSummarization: false },
|
|
62
|
-
continuity: { minScoreForSeamless: 0.7, topicDecayHours: 48 }
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
const worker = new ConsolidationWorker(workingSetStore as any, consolidatedStore as any, config);
|
|
66
|
-
const out = await worker.forceRunWithReport();
|
|
67
|
-
|
|
68
|
-
expect(out.consolidatedCount).toBeGreaterThan(0);
|
|
69
|
-
expect(out.promotedRuleCount).toBeGreaterThan(0);
|
|
70
|
-
expect(out.report.beforeTokenEstimate).toBeGreaterThan(0);
|
|
71
|
-
expect(out.report.reductionRatio).toBeGreaterThanOrEqual(0);
|
|
72
|
-
expect(out.report.qualityGuardPassed).toBe(true);
|
|
73
|
-
expect(rules[0]?.sourceMemoryIds?.length).toBeGreaterThan(0);
|
|
74
|
-
});
|
|
75
|
-
});
|
|
@@ -1,282 +0,0 @@
|
|
|
1
|
-
import * as path from 'path';
|
|
2
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
createEmbeddingMaintenanceService,
|
|
6
|
-
type EmbeddingMaintenanceFileSystem
|
|
7
|
-
} from '../../src/core/engine/embedding-maintenance-service.js';
|
|
8
|
-
|
|
9
|
-
function event(id: string, content = `content for ${id}`) {
|
|
10
|
-
return { id, content };
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function createHarness(options?: {
|
|
14
|
-
currentModel?: string;
|
|
15
|
-
vectorCount?: number;
|
|
16
|
-
files?: Record<string, string>;
|
|
17
|
-
workerRunning?: boolean;
|
|
18
|
-
nullWorker?: boolean;
|
|
19
|
-
events?: Array<{ id: string; content: string }>;
|
|
20
|
-
}) {
|
|
21
|
-
const storagePath = '/memory-root/project-a';
|
|
22
|
-
const metaPath = path.join(storagePath, 'embedding-meta.json');
|
|
23
|
-
const files = new Map<string, string>(Object.entries(options?.files ?? {}));
|
|
24
|
-
const calls: string[] = [];
|
|
25
|
-
|
|
26
|
-
const fileSystem: EmbeddingMaintenanceFileSystem = {
|
|
27
|
-
existsSync: vi.fn((targetPath: string) => files.has(targetPath)),
|
|
28
|
-
readFileSync: vi.fn((targetPath: string) => files.get(targetPath) ?? ''),
|
|
29
|
-
writeFileSync: vi.fn((targetPath: string, content: string) => {
|
|
30
|
-
files.set(targetPath, content);
|
|
31
|
-
})
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const initialize = vi.fn(async () => {
|
|
35
|
-
calls.push('initialize');
|
|
36
|
-
});
|
|
37
|
-
const vectorStore = {
|
|
38
|
-
count: vi.fn(async () => options?.vectorCount ?? 0),
|
|
39
|
-
clearAll: vi.fn(async () => {
|
|
40
|
-
calls.push('clear-vectors');
|
|
41
|
-
})
|
|
42
|
-
};
|
|
43
|
-
const events = options?.events ?? [];
|
|
44
|
-
const eventStore = {
|
|
45
|
-
clearEmbeddingOutbox: vi.fn(async () => {
|
|
46
|
-
calls.push('clear-outbox');
|
|
47
|
-
}),
|
|
48
|
-
getEventsPage: vi.fn(async (limit: number, offset: number) => events.slice(offset, offset + limit)),
|
|
49
|
-
enqueueForEmbedding: vi.fn(async (eventId: string, _content: string) => {
|
|
50
|
-
calls.push(`enqueue:${eventId}`);
|
|
51
|
-
})
|
|
52
|
-
};
|
|
53
|
-
const worker = {
|
|
54
|
-
isRunning: vi.fn(() => options?.workerRunning ?? false),
|
|
55
|
-
stop: vi.fn(() => {
|
|
56
|
-
calls.push('stop-worker');
|
|
57
|
-
}),
|
|
58
|
-
start: vi.fn(() => {
|
|
59
|
-
calls.push('start-worker');
|
|
60
|
-
})
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
const service = createEmbeddingMaintenanceService({
|
|
64
|
-
storagePath,
|
|
65
|
-
initialize,
|
|
66
|
-
getEmbeddingModelName: vi.fn(() => options?.currentModel ?? 'embedding-model-a'),
|
|
67
|
-
vectorStore,
|
|
68
|
-
eventStore,
|
|
69
|
-
getVectorWorker: () => (options?.nullWorker ? null : worker),
|
|
70
|
-
fileSystem
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
return {
|
|
74
|
-
service,
|
|
75
|
-
storagePath,
|
|
76
|
-
metaPath,
|
|
77
|
-
files,
|
|
78
|
-
calls,
|
|
79
|
-
fileSystem,
|
|
80
|
-
initialize,
|
|
81
|
-
vectorStore,
|
|
82
|
-
eventStore,
|
|
83
|
-
worker
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
describe('EmbeddingMaintenanceService', () => {
|
|
88
|
-
it('initializes embedding metadata when no prior vectors exist', async () => {
|
|
89
|
-
const h = createHarness({ vectorCount: 0 });
|
|
90
|
-
|
|
91
|
-
const result = await h.service.ensureEmbeddingModelForImport();
|
|
92
|
-
|
|
93
|
-
expect(result).toEqual({
|
|
94
|
-
changed: false,
|
|
95
|
-
previousModel: null,
|
|
96
|
-
currentModel: 'embedding-model-a',
|
|
97
|
-
enqueued: 0,
|
|
98
|
-
reason: 'initialized-meta'
|
|
99
|
-
});
|
|
100
|
-
expect(h.initialize).toHaveBeenCalledTimes(1);
|
|
101
|
-
expect(h.vectorStore.count).toHaveBeenCalledTimes(1);
|
|
102
|
-
expect(h.vectorStore.clearAll).not.toHaveBeenCalled();
|
|
103
|
-
expect(h.eventStore.clearEmbeddingOutbox).not.toHaveBeenCalled();
|
|
104
|
-
expect(JSON.parse(h.files.get(h.metaPath)!)).toMatchObject({
|
|
105
|
-
model: 'embedding-model-a',
|
|
106
|
-
updatedAt: expect.any(String)
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it('returns unchanged when stored metadata already matches the current model', async () => {
|
|
111
|
-
const metaPath = path.join('/memory-root/project-a', 'embedding-meta.json');
|
|
112
|
-
const h = createHarness({
|
|
113
|
-
vectorCount: 5,
|
|
114
|
-
files: {
|
|
115
|
-
[metaPath]: JSON.stringify({ model: 'embedding-model-a', updatedAt: '2026-05-02T00:00:00.000Z' })
|
|
116
|
-
}
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
const result = await h.service.ensureEmbeddingModelForImport();
|
|
120
|
-
|
|
121
|
-
expect(result).toEqual({
|
|
122
|
-
changed: false,
|
|
123
|
-
previousModel: 'embedding-model-a',
|
|
124
|
-
currentModel: 'embedding-model-a',
|
|
125
|
-
enqueued: 0
|
|
126
|
-
});
|
|
127
|
-
expect(h.fileSystem.writeFileSync).not.toHaveBeenCalled();
|
|
128
|
-
expect(h.vectorStore.clearAll).not.toHaveBeenCalled();
|
|
129
|
-
expect(h.eventStore.clearEmbeddingOutbox).not.toHaveBeenCalled();
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
it('reports a dry-run model mismatch without clearing vectors or outbox state', async () => {
|
|
133
|
-
const metaPath = path.join('/memory-root/project-a', 'embedding-meta.json');
|
|
134
|
-
const h = createHarness({
|
|
135
|
-
currentModel: 'embedding-model-b',
|
|
136
|
-
vectorCount: 2,
|
|
137
|
-
files: {
|
|
138
|
-
[metaPath]: JSON.stringify({ model: 'embedding-model-a' })
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
const result = await h.service.ensureEmbeddingModelForImport({ autoMigrate: false });
|
|
143
|
-
|
|
144
|
-
expect(result).toEqual({
|
|
145
|
-
changed: true,
|
|
146
|
-
previousModel: 'embedding-model-a',
|
|
147
|
-
currentModel: 'embedding-model-b',
|
|
148
|
-
enqueued: 0,
|
|
149
|
-
reason: 'model-mismatch'
|
|
150
|
-
});
|
|
151
|
-
expect(h.vectorStore.clearAll).not.toHaveBeenCalled();
|
|
152
|
-
expect(h.eventStore.clearEmbeddingOutbox).not.toHaveBeenCalled();
|
|
153
|
-
expect(h.eventStore.enqueueForEmbedding).not.toHaveBeenCalled();
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
it('reports legacy vectors without metadata as a dry-run migration requirement', async () => {
|
|
157
|
-
const h = createHarness({ vectorCount: 3 });
|
|
158
|
-
|
|
159
|
-
const result = await h.service.ensureEmbeddingModelForImport({ autoMigrate: false });
|
|
160
|
-
|
|
161
|
-
expect(result).toEqual({
|
|
162
|
-
changed: true,
|
|
163
|
-
previousModel: null,
|
|
164
|
-
currentModel: 'embedding-model-a',
|
|
165
|
-
enqueued: 0,
|
|
166
|
-
reason: 'legacy-vectors-without-meta'
|
|
167
|
-
});
|
|
168
|
-
expect(h.fileSystem.writeFileSync).not.toHaveBeenCalled();
|
|
169
|
-
expect(h.vectorStore.clearAll).not.toHaveBeenCalled();
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
it('migrates vectors by clearing indexes, re-enqueueing events, and restarting a running worker', async () => {
|
|
173
|
-
const metaPath = path.join('/memory-root/project-a', 'embedding-meta.json');
|
|
174
|
-
const h = createHarness({
|
|
175
|
-
currentModel: 'embedding-model-b',
|
|
176
|
-
vectorCount: 10,
|
|
177
|
-
workerRunning: true,
|
|
178
|
-
files: {
|
|
179
|
-
[metaPath]: JSON.stringify({ model: 'embedding-model-a' })
|
|
180
|
-
},
|
|
181
|
-
events: [event('e1', 'first memory'), event('e2', 'second memory')]
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
const result = await h.service.ensureEmbeddingModelForImport();
|
|
185
|
-
|
|
186
|
-
expect(result).toEqual({
|
|
187
|
-
changed: true,
|
|
188
|
-
previousModel: 'embedding-model-a',
|
|
189
|
-
currentModel: 'embedding-model-b',
|
|
190
|
-
enqueued: 2,
|
|
191
|
-
reason: 'model-mismatch'
|
|
192
|
-
});
|
|
193
|
-
expect(h.calls).toEqual([
|
|
194
|
-
'initialize',
|
|
195
|
-
'stop-worker',
|
|
196
|
-
'clear-vectors',
|
|
197
|
-
'clear-outbox',
|
|
198
|
-
'enqueue:e1',
|
|
199
|
-
'enqueue:e2',
|
|
200
|
-
'start-worker'
|
|
201
|
-
]);
|
|
202
|
-
expect(h.eventStore.getEventsPage).toHaveBeenCalledWith(1000, 0);
|
|
203
|
-
expect(h.eventStore.enqueueForEmbedding).toHaveBeenNthCalledWith(1, 'e1', 'first memory');
|
|
204
|
-
expect(h.eventStore.enqueueForEmbedding).toHaveBeenNthCalledWith(2, 'e2', 'second memory');
|
|
205
|
-
expect(JSON.parse(h.files.get(h.metaPath)!)).toMatchObject({
|
|
206
|
-
model: 'embedding-model-b',
|
|
207
|
-
previousModel: 'embedding-model-a',
|
|
208
|
-
migratedAt: expect.any(String),
|
|
209
|
-
enqueued: 2
|
|
210
|
-
});
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
it('auto-migrates legacy vectors without metadata and does not restart an idle worker', async () => {
|
|
214
|
-
const h = createHarness({
|
|
215
|
-
vectorCount: 3,
|
|
216
|
-
workerRunning: false,
|
|
217
|
-
events: [event('legacy-1', 'legacy memory')]
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
const result = await h.service.ensureEmbeddingModelForImport();
|
|
221
|
-
|
|
222
|
-
expect(result).toEqual({
|
|
223
|
-
changed: true,
|
|
224
|
-
previousModel: null,
|
|
225
|
-
currentModel: 'embedding-model-a',
|
|
226
|
-
enqueued: 1,
|
|
227
|
-
reason: 'legacy-vectors-without-meta'
|
|
228
|
-
});
|
|
229
|
-
expect(h.worker.stop).not.toHaveBeenCalled();
|
|
230
|
-
expect(h.worker.start).not.toHaveBeenCalled();
|
|
231
|
-
expect(h.calls).toEqual(['initialize', 'clear-vectors', 'clear-outbox', 'enqueue:legacy-1']);
|
|
232
|
-
expect(JSON.parse(h.files.get(h.metaPath)!)).toMatchObject({
|
|
233
|
-
model: 'embedding-model-a',
|
|
234
|
-
previousModel: null,
|
|
235
|
-
migratedAt: expect.any(String),
|
|
236
|
-
enqueued: 1
|
|
237
|
-
});
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
it('re-enqueues events across page boundaries during migration', async () => {
|
|
241
|
-
const metaPath = path.join('/memory-root/project-a', 'embedding-meta.json');
|
|
242
|
-
const events = Array.from({ length: 1001 }, (_, index) => event(`event-${index + 1}`));
|
|
243
|
-
const h = createHarness({
|
|
244
|
-
currentModel: 'embedding-model-b',
|
|
245
|
-
vectorCount: 1001,
|
|
246
|
-
files: {
|
|
247
|
-
[metaPath]: JSON.stringify({ model: 'embedding-model-a' })
|
|
248
|
-
},
|
|
249
|
-
events
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
const result = await h.service.ensureEmbeddingModelForImport();
|
|
253
|
-
|
|
254
|
-
expect(result.enqueued).toBe(1001);
|
|
255
|
-
expect(h.eventStore.getEventsPage).toHaveBeenNthCalledWith(1, 1000, 0);
|
|
256
|
-
expect(h.eventStore.getEventsPage).toHaveBeenNthCalledWith(2, 1000, 1000);
|
|
257
|
-
expect(h.eventStore.getEventsPage).toHaveBeenCalledTimes(2);
|
|
258
|
-
expect(h.eventStore.enqueueForEmbedding).toHaveBeenCalledTimes(1001);
|
|
259
|
-
expect(h.eventStore.enqueueForEmbedding).toHaveBeenNthCalledWith(1001, 'event-1001', 'content for event-1001');
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
it('migrates without worker lifecycle calls when no vector worker is available', async () => {
|
|
263
|
-
const metaPath = path.join('/memory-root/project-a', 'embedding-meta.json');
|
|
264
|
-
const h = createHarness({
|
|
265
|
-
currentModel: 'embedding-model-b',
|
|
266
|
-
vectorCount: 1,
|
|
267
|
-
nullWorker: true,
|
|
268
|
-
files: {
|
|
269
|
-
[metaPath]: JSON.stringify({ model: 'embedding-model-a' })
|
|
270
|
-
},
|
|
271
|
-
events: [event('e1')]
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
const result = await h.service.ensureEmbeddingModelForImport();
|
|
275
|
-
|
|
276
|
-
expect(result.enqueued).toBe(1);
|
|
277
|
-
expect(h.calls).toEqual(['initialize', 'clear-vectors', 'clear-outbox', 'enqueue:e1']);
|
|
278
|
-
expect(h.worker.isRunning).not.toHaveBeenCalled();
|
|
279
|
-
expect(h.worker.stop).not.toHaveBeenCalled();
|
|
280
|
-
expect(h.worker.start).not.toHaveBeenCalled();
|
|
281
|
-
});
|
|
282
|
-
});
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for Evidence Aligner
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { describe, it, expect } from 'vitest';
|
|
6
|
-
import { EvidenceAligner } from '../../src/core/evidence-aligner.js';
|
|
7
|
-
|
|
8
|
-
describe('EvidenceAligner', () => {
|
|
9
|
-
const aligner = new EvidenceAligner();
|
|
10
|
-
|
|
11
|
-
describe('align', () => {
|
|
12
|
-
it('should find exact matches', () => {
|
|
13
|
-
const claims = ['the quick brown fox'];
|
|
14
|
-
const source = 'The quick brown fox jumps over the lazy dog.';
|
|
15
|
-
|
|
16
|
-
const result = aligner.align(claims, source);
|
|
17
|
-
|
|
18
|
-
expect(result.isAligned).toBe(true);
|
|
19
|
-
expect(result.spans.length).toBe(1);
|
|
20
|
-
expect(result.spans[0].matchType).toBe('exact');
|
|
21
|
-
expect(result.spans[0].confidence).toBe(1.0);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('should find fuzzy matches', () => {
|
|
25
|
-
const claims = ['quick brown fox jumping'];
|
|
26
|
-
const source = 'The quick brown fox jumps over the lazy dog.';
|
|
27
|
-
|
|
28
|
-
const result = aligner.align(claims, source);
|
|
29
|
-
|
|
30
|
-
// May or may not find fuzzy match depending on threshold
|
|
31
|
-
expect(result.confidence).toBeGreaterThanOrEqual(0);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('should report missing claims', () => {
|
|
35
|
-
const claims = ['completely unrelated content'];
|
|
36
|
-
const source = 'The quick brown fox jumps over the lazy dog.';
|
|
37
|
-
|
|
38
|
-
const result = aligner.align(claims, source);
|
|
39
|
-
|
|
40
|
-
expect(result.missingClaims.length).toBe(1);
|
|
41
|
-
expect(result.missingClaims[0]).toBe('completely unrelated content');
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('should skip short claims', () => {
|
|
45
|
-
const claims = ['short'];
|
|
46
|
-
const source = 'This is a short test.';
|
|
47
|
-
|
|
48
|
-
const result = aligner.align(claims, source);
|
|
49
|
-
|
|
50
|
-
// Short claims are skipped
|
|
51
|
-
expect(result.spans.length).toBe(0);
|
|
52
|
-
expect(result.missingClaims.length).toBe(0);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('should calculate correct confidence', () => {
|
|
56
|
-
const claims = [
|
|
57
|
-
'the quick brown fox',
|
|
58
|
-
'jumps over the lazy dog'
|
|
59
|
-
];
|
|
60
|
-
const source = 'The quick brown fox jumps over the lazy dog.';
|
|
61
|
-
|
|
62
|
-
const result = aligner.align(claims, source);
|
|
63
|
-
|
|
64
|
-
expect(result.confidence).toBeGreaterThan(0.5);
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
describe('extractClaims', () => {
|
|
69
|
-
it('should split text into sentences', () => {
|
|
70
|
-
const text = 'First sentence. Second sentence. Third sentence.';
|
|
71
|
-
const claims = aligner.extractClaims(text);
|
|
72
|
-
|
|
73
|
-
expect(claims.length).toBe(3);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('should filter out questions', () => {
|
|
77
|
-
const text = 'This is a statement. Is this a question?';
|
|
78
|
-
const claims = aligner.extractClaims(text);
|
|
79
|
-
|
|
80
|
-
expect(claims.length).toBe(1);
|
|
81
|
-
expect(claims[0]).not.toContain('?');
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it('should filter out short sentences', () => {
|
|
85
|
-
const text = 'Hi. This is a longer sentence that should be included.';
|
|
86
|
-
const claims = aligner.extractClaims(text);
|
|
87
|
-
|
|
88
|
-
// "Hi" is too short
|
|
89
|
-
expect(claims.some(c => c === 'Hi')).toBe(false);
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
describe('verifyGrounding', () => {
|
|
94
|
-
it('should verify response is grounded in context', () => {
|
|
95
|
-
const response = 'The fox is quick and brown.';
|
|
96
|
-
const context = [
|
|
97
|
-
'The quick brown fox jumps over the lazy dog.',
|
|
98
|
-
'Foxes are known for their speed.'
|
|
99
|
-
];
|
|
100
|
-
|
|
101
|
-
const result = aligner.verifyGrounding(response, context);
|
|
102
|
-
|
|
103
|
-
expect(result.isAligned).toBe(true);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it('should detect ungrounded responses', () => {
|
|
107
|
-
const response = 'Elephants are the largest land animals.';
|
|
108
|
-
const context = [
|
|
109
|
-
'The quick brown fox jumps over the lazy dog.'
|
|
110
|
-
];
|
|
111
|
-
|
|
112
|
-
const result = aligner.verifyGrounding(response, context);
|
|
113
|
-
|
|
114
|
-
expect(result.missingClaims.length).toBeGreaterThan(0);
|
|
115
|
-
});
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
describe('custom options', () => {
|
|
119
|
-
it('should use custom fuzzy threshold', () => {
|
|
120
|
-
const strictAligner = new EvidenceAligner({
|
|
121
|
-
fuzzyThreshold: 0.95
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
const claims = ['quick brown foxes'];
|
|
125
|
-
const source = 'The quick brown fox jumps.';
|
|
126
|
-
|
|
127
|
-
const result = strictAligner.align(claims, source);
|
|
128
|
-
|
|
129
|
-
// Strict threshold should result in no match
|
|
130
|
-
expect(result.spans.length).toBe(0);
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
it('should use custom max missing claims', () => {
|
|
134
|
-
const tolerantAligner = new EvidenceAligner({
|
|
135
|
-
maxMissingClaims: 5
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
const claims = [
|
|
139
|
-
'claim one that exists',
|
|
140
|
-
'claim two missing',
|
|
141
|
-
'claim three missing',
|
|
142
|
-
'claim four missing'
|
|
143
|
-
];
|
|
144
|
-
const source = 'This source contains claim one that exists.';
|
|
145
|
-
|
|
146
|
-
const result = tolerantAligner.align(claims, source);
|
|
147
|
-
|
|
148
|
-
// Should still be aligned with 3 missing claims (< 5)
|
|
149
|
-
expect(result.isAligned).toBe(true);
|
|
150
|
-
});
|
|
151
|
-
});
|
|
152
|
-
});
|