@traqr/memory 0.1.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/README.md +135 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/auth.d.ts +18 -0
- package/dist/lib/auth.d.ts.map +1 -0
- package/dist/lib/auth.js +31 -0
- package/dist/lib/auth.js.map +1 -0
- package/dist/lib/auto-derive.d.ts +35 -0
- package/dist/lib/auto-derive.js +261 -0
- package/dist/lib/auto-derive.js.map +1 -0
- package/dist/lib/borderline.d.ts +26 -0
- package/dist/lib/borderline.js +121 -0
- package/dist/lib/borderline.js.map +1 -0
- package/dist/lib/client.d.ts +28 -0
- package/dist/lib/client.d.ts.map +1 -0
- package/dist/lib/client.js +60 -0
- package/dist/lib/client.js.map +1 -0
- package/dist/lib/context.d.ts +38 -0
- package/dist/lib/context.d.ts.map +1 -0
- package/dist/lib/context.js +334 -0
- package/dist/lib/context.js.map +1 -0
- package/dist/lib/embeddings.d.ts +60 -0
- package/dist/lib/embeddings.d.ts.map +1 -0
- package/dist/lib/embeddings.js +229 -0
- package/dist/lib/embeddings.js.map +1 -0
- package/dist/lib/entity-pipeline.d.ts +23 -0
- package/dist/lib/entity-pipeline.js +151 -0
- package/dist/lib/entity-pipeline.js.map +1 -0
- package/dist/lib/formatting.d.ts +13 -0
- package/dist/lib/formatting.d.ts.map +1 -0
- package/dist/lib/formatting.js +60 -0
- package/dist/lib/formatting.js.map +1 -0
- package/dist/lib/learning-extractor.d.ts +144 -0
- package/dist/lib/learning-extractor.d.ts.map +1 -0
- package/dist/lib/learning-extractor.js +921 -0
- package/dist/lib/learning-extractor.js.map +1 -0
- package/dist/lib/lifecycle.d.ts +45 -0
- package/dist/lib/lifecycle.js +84 -0
- package/dist/lib/lifecycle.js.map +1 -0
- package/dist/lib/memory.d.ts +128 -0
- package/dist/lib/memory.d.ts.map +1 -0
- package/dist/lib/memory.js +590 -0
- package/dist/lib/memory.js.map +1 -0
- package/dist/lib/quality-gate.d.ts +32 -0
- package/dist/lib/quality-gate.js +158 -0
- package/dist/lib/quality-gate.js.map +1 -0
- package/dist/lib/quality-gate.test.d.ts +7 -0
- package/dist/lib/quality-gate.test.js +75 -0
- package/dist/lib/quality-gate.test.js.map +1 -0
- package/dist/lib/rerank.d.ts +22 -0
- package/dist/lib/rerank.js +61 -0
- package/dist/lib/rerank.js.map +1 -0
- package/dist/lib/retrieval.d.ts +75 -0
- package/dist/lib/retrieval.js +380 -0
- package/dist/lib/retrieval.js.map +1 -0
- package/dist/migrate.d.ts +17 -0
- package/dist/migrate.d.ts.map +1 -0
- package/dist/migrate.js +81 -0
- package/dist/migrate.js.map +1 -0
- package/dist/routes/analyze-codebase.d.ts +9 -0
- package/dist/routes/analyze-codebase.d.ts.map +1 -0
- package/dist/routes/analyze-codebase.js +70 -0
- package/dist/routes/analyze-codebase.js.map +1 -0
- package/dist/routes/analyze-voice.d.ts +9 -0
- package/dist/routes/analyze-voice.d.ts.map +1 -0
- package/dist/routes/analyze-voice.js +63 -0
- package/dist/routes/analyze-voice.js.map +1 -0
- package/dist/routes/assemble-context.d.ts +9 -0
- package/dist/routes/assemble-context.d.ts.map +1 -0
- package/dist/routes/assemble-context.js +68 -0
- package/dist/routes/assemble-context.js.map +1 -0
- package/dist/routes/bootstrap.d.ts +12 -0
- package/dist/routes/bootstrap.d.ts.map +1 -0
- package/dist/routes/bootstrap.js +102 -0
- package/dist/routes/bootstrap.js.map +1 -0
- package/dist/routes/browse.d.ts +11 -0
- package/dist/routes/browse.js +85 -0
- package/dist/routes/browse.js.map +1 -0
- package/dist/routes/capture-thought.d.ts +13 -0
- package/dist/routes/capture-thought.d.ts.map +1 -0
- package/dist/routes/capture-thought.js +178 -0
- package/dist/routes/capture-thought.js.map +1 -0
- package/dist/routes/capture.d.ts +13 -0
- package/dist/routes/capture.d.ts.map +1 -0
- package/dist/routes/capture.js +86 -0
- package/dist/routes/capture.js.map +1 -0
- package/dist/routes/cite.d.ts +9 -0
- package/dist/routes/cite.d.ts.map +1 -0
- package/dist/routes/cite.js +49 -0
- package/dist/routes/cite.js.map +1 -0
- package/dist/routes/crud.d.ts +11 -0
- package/dist/routes/crud.d.ts.map +1 -0
- package/dist/routes/crud.js +176 -0
- package/dist/routes/crud.js.map +1 -0
- package/dist/routes/dashboard.d.ts +9 -0
- package/dist/routes/dashboard.d.ts.map +1 -0
- package/dist/routes/dashboard.js +85 -0
- package/dist/routes/dashboard.js.map +1 -0
- package/dist/routes/entity-cron.d.ts +8 -0
- package/dist/routes/entity-cron.js +31 -0
- package/dist/routes/entity-cron.js.map +1 -0
- package/dist/routes/export.d.ts +8 -0
- package/dist/routes/export.d.ts.map +1 -0
- package/dist/routes/export.js +69 -0
- package/dist/routes/export.js.map +1 -0
- package/dist/routes/extract-pr-learnings.d.ts +12 -0
- package/dist/routes/extract-pr-learnings.d.ts.map +1 -0
- package/dist/routes/extract-pr-learnings.js +127 -0
- package/dist/routes/extract-pr-learnings.js.map +1 -0
- package/dist/routes/forget-cron.d.ts +9 -0
- package/dist/routes/forget-cron.js +30 -0
- package/dist/routes/forget-cron.js.map +1 -0
- package/dist/routes/learnings.d.ts +9 -0
- package/dist/routes/learnings.d.ts.map +1 -0
- package/dist/routes/learnings.js +237 -0
- package/dist/routes/learnings.js.map +1 -0
- package/dist/routes/pulse.d.ts +9 -0
- package/dist/routes/pulse.d.ts.map +1 -0
- package/dist/routes/pulse.js +133 -0
- package/dist/routes/pulse.js.map +1 -0
- package/dist/routes/search.d.ts +8 -0
- package/dist/routes/search.d.ts.map +1 -0
- package/dist/routes/search.js +107 -0
- package/dist/routes/search.js.map +1 -0
- package/dist/routes/store.d.ts +8 -0
- package/dist/routes/store.d.ts.map +1 -0
- package/dist/routes/store.js +89 -0
- package/dist/routes/store.js.map +1 -0
- package/dist/routes/sync.d.ts +12 -0
- package/dist/routes/sync.d.ts.map +1 -0
- package/dist/routes/sync.js +83 -0
- package/dist/routes/sync.js.map +1 -0
- package/dist/routes/voice-profile.d.ts +9 -0
- package/dist/routes/voice-profile.d.ts.map +1 -0
- package/dist/routes/voice-profile.js +124 -0
- package/dist/routes/voice-profile.js.map +1 -0
- package/dist/server.d.ts +37 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +99 -0
- package/dist/server.js.map +1 -0
- package/dist/vectordb/index.d.ts +17 -0
- package/dist/vectordb/index.d.ts.map +1 -0
- package/dist/vectordb/index.js +39 -0
- package/dist/vectordb/index.js.map +1 -0
- package/dist/vectordb/supabase.d.ts +62 -0
- package/dist/vectordb/supabase.d.ts.map +1 -0
- package/dist/vectordb/supabase.js +711 -0
- package/dist/vectordb/supabase.js.map +1 -0
- package/dist/vectordb/types.d.ts +217 -0
- package/dist/vectordb/types.d.ts.map +1 -0
- package/dist/vectordb/types.js +28 -0
- package/dist/vectordb/types.js.map +1 -0
- package/package.json +49 -0
- package/setup.sql +1037 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quality Gate v2 — Domain-Agnostic Memory Validation
|
|
3
|
+
*
|
|
4
|
+
* Three-layer architecture:
|
|
5
|
+
* Layer 1: Universal rejection (42 banned phrase regexes)
|
|
6
|
+
* Layer 2: Universal specificity (16 domain-agnostic markers)
|
|
7
|
+
* Layer 3: Code-specific boost (6 additive code markers)
|
|
8
|
+
*
|
|
9
|
+
* Three gate modes:
|
|
10
|
+
* - Strict gate: LLM extraction pipeline (≥3 markers, ≥80 chars, confidence ≥0.85)
|
|
11
|
+
* - Ingestion gate: MCP tools / agent writes (≥2 markers, ≥30 chars)
|
|
12
|
+
* - Light gate: Life Import bulk (≥20 chars, banned phrases only)
|
|
13
|
+
*
|
|
14
|
+
* ADR: [[MCP Redesign — Quality Gate v2]]
|
|
15
|
+
*/
|
|
16
|
+
// ============================================================
|
|
17
|
+
// Layer 1: Banned Phrases — content matching any is rejected
|
|
18
|
+
// ============================================================
|
|
19
|
+
export const BANNED_PHRASES = [
|
|
20
|
+
/\bbe careful\b/i,
|
|
21
|
+
/\bremember to\b/i,
|
|
22
|
+
/\balways make sure\b/i,
|
|
23
|
+
/\bconsider /i,
|
|
24
|
+
/\bthink about\b/i,
|
|
25
|
+
/\bdon't forget\b/i,
|
|
26
|
+
/\bpromoting\b.*\bseparation of concerns\b/i,
|
|
27
|
+
/\bcleaner\b.*\barchitecture\b/i,
|
|
28
|
+
/\bbest practice/i,
|
|
29
|
+
/\bensur(?:es?|ing)\b.*\bmaintainab/i,
|
|
30
|
+
/\bimportant to\b/i,
|
|
31
|
+
/\bkeep in mind\b/i,
|
|
32
|
+
/\bworth noting\b/i,
|
|
33
|
+
/\bhelps with\b/i,
|
|
34
|
+
/\bimproves?\b.*\breadability\b/i,
|
|
35
|
+
/\b(demonstrates?|suggests?|indicates?)\s+a\s+preference\b/i,
|
|
36
|
+
/\b(promoting|enhancing|improving)\s+(readability|maintainability)\b/i,
|
|
37
|
+
/\bcognitive load\b/i,
|
|
38
|
+
/\bindicating\b.*\b(value|preference|focus)\b/i,
|
|
39
|
+
/\bhighlighting\b.*\b(importance|value|preference)\b/i,
|
|
40
|
+
/\breflecting\b.*\b(design choice|preference|value)\b/i,
|
|
41
|
+
/\bfacilitating\b.*\b(easier|better|improved)\b/i,
|
|
42
|
+
/\b(this|the)\s+(approach|modification|update|change)\s+(aids?|revealed?)\b/i,
|
|
43
|
+
/\binforms?\s+future\s+developers?\b/i,
|
|
44
|
+
/\baids?\s+future\s+developers?\b/i,
|
|
45
|
+
/\bsave\s+time\s+for\s+future\b/i,
|
|
46
|
+
];
|
|
47
|
+
// ============================================================
|
|
48
|
+
// Layer 2: Universal Specificity Markers (16 patterns)
|
|
49
|
+
// Fire on ANY domain — dev, health, finance, cooking, personal.
|
|
50
|
+
// ============================================================
|
|
51
|
+
export const UNIVERSAL_SPECIFICITY_MARKERS = [
|
|
52
|
+
// Identity + judgment (existing, reclassified)
|
|
53
|
+
/\bSean\b/,
|
|
54
|
+
/\b(prefers?|prioritizes?|values?|avoids?|hates?|loves?)\b/i,
|
|
55
|
+
/\b(decided|chose|picked|rejected|ruled out)\b/i,
|
|
56
|
+
/\b(because|reason|rationale|motivation|why)\b/i,
|
|
57
|
+
/\b(goal|vision|strategy|roadmap|north star)\b/i,
|
|
58
|
+
// Quantitative + structural (existing, reclassified)
|
|
59
|
+
/\b\d{2,}\b/,
|
|
60
|
+
// NEW universal markers
|
|
61
|
+
/\b(always|never|every time|mandatory)\b/i,
|
|
62
|
+
/\b(instead of|rather than|not|unlike)\b/i,
|
|
63
|
+
/\b(discovered|learned|realized|found out)\b/i,
|
|
64
|
+
/\b(broke|failed|crashed|bug|error)\b/i,
|
|
65
|
+
/"[^"]{3,}"/,
|
|
66
|
+
/\b[A-Z]{2,}\b/,
|
|
67
|
+
/\b(recipe|ingredient|medication|dosage|blood|allergy|diagnosis|symptom|weight|calories)\b/i,
|
|
68
|
+
/\b(company|stock|portfolio|invest)\b/i,
|
|
69
|
+
/\b(deadline|meeting|project|sprint)\b/i,
|
|
70
|
+
/\w+\.\w+/,
|
|
71
|
+
];
|
|
72
|
+
// ============================================================
|
|
73
|
+
// Layer 3: Code-Specific Markers (6 patterns, additive boost)
|
|
74
|
+
// Only fire on content with code artifacts. Never required.
|
|
75
|
+
// ============================================================
|
|
76
|
+
export const CODE_SPECIFICITY_MARKERS = [
|
|
77
|
+
/`[^`]+`/,
|
|
78
|
+
/\.(ts|tsx|js|jsx|md|json|sql|sh|py|rs|go)/,
|
|
79
|
+
/[A-Z][a-z]+[A-Z]/,
|
|
80
|
+
/\b(src|lib|app|api|components|packages)\//,
|
|
81
|
+
/\w+\([^)]*\)/,
|
|
82
|
+
/\b(function|const|export|import|interface|type)\b/i,
|
|
83
|
+
];
|
|
84
|
+
// Backward-compatible union export
|
|
85
|
+
export const SPECIFICITY_MARKERS = [...UNIVERSAL_SPECIFICITY_MARKERS, ...CODE_SPECIFICITY_MARKERS];
|
|
86
|
+
// ============================================================
|
|
87
|
+
// Fluff Patterns — generic LLM-speak that adds no value
|
|
88
|
+
// ============================================================
|
|
89
|
+
export const FLUFF_PATTERNS = [
|
|
90
|
+
/\b(promotes?|ensures?|improves?|enables?|facilitates?|leverages?)\b.*\b(cleaner|better|proper|good|robust|maintainable|scalable|readable|modular)\b/i,
|
|
91
|
+
/\b(this|the)\s+(approach|pattern|modification|change|update)\b.*\b(helps?|allows?|supports?|shows? how)\b/i,
|
|
92
|
+
/\badopt the pattern\b/i,
|
|
93
|
+
/\b(demonstrates?|suggests?|indicates?|showcases?|illustrates?|highlights?|reveals?)\s+(a\s+)?(preference|value|focus|priority)\s+(for|on|in)\b/i,
|
|
94
|
+
/\b(modular|scalable|maintainable|readable)\b.*\b(code|design|architecture)\b/i,
|
|
95
|
+
/\b(separation of concerns|single responsibility|DRY principle)\b/i,
|
|
96
|
+
/\b(enhancing|improving|promoting)\s+(readability|maintainability|scalability|reusability)\b/i,
|
|
97
|
+
/\bthe\s+(drastic|extensive|deliberate|significant|major)\s+(reduction|insertion|removal|update|change)\b.*\b(indicates?|suggests?|shows?)\b/i,
|
|
98
|
+
/\bensuring\s+(comprehensive|thorough|complete)\s+(testing|coverage|validation)\b/i,
|
|
99
|
+
/\b(extensive|significant|large)\s+(insertion|addition|deletion|removal)\s+of\s+\d+/i,
|
|
100
|
+
];
|
|
101
|
+
// ============================================================
|
|
102
|
+
// Scoring
|
|
103
|
+
// ============================================================
|
|
104
|
+
function countSpecificityMarkers(content) {
|
|
105
|
+
const universal = UNIVERSAL_SPECIFICITY_MARKERS.filter(p => p.test(content)).length;
|
|
106
|
+
const code = CODE_SPECIFICITY_MARKERS.filter(p => p.test(content)).length;
|
|
107
|
+
return universal + code;
|
|
108
|
+
}
|
|
109
|
+
// ============================================================
|
|
110
|
+
// Strict Gate — LLM extraction pipeline
|
|
111
|
+
// ============================================================
|
|
112
|
+
export function passesQualityGate(learning) {
|
|
113
|
+
if (learning.confidence < 0.85)
|
|
114
|
+
return false;
|
|
115
|
+
if (learning.content.length < 80)
|
|
116
|
+
return false;
|
|
117
|
+
if (countSpecificityMarkers(learning.content) < 3)
|
|
118
|
+
return false;
|
|
119
|
+
if (BANNED_PHRASES.some(r => r.test(learning.content)))
|
|
120
|
+
return false;
|
|
121
|
+
if (FLUFF_PATTERNS.some(r => r.test(learning.content)))
|
|
122
|
+
return false;
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
// ============================================================
|
|
126
|
+
// Ingestion Gate — MCP tools, agent writes, pulse
|
|
127
|
+
// ============================================================
|
|
128
|
+
export function passesIngestionGate(content) {
|
|
129
|
+
if (content.length < 30) {
|
|
130
|
+
return { passes: false, reason: 'Content too short (min 30 chars)' };
|
|
131
|
+
}
|
|
132
|
+
const hasBannedPhrase = BANNED_PHRASES.some(r => r.test(content));
|
|
133
|
+
if (hasBannedPhrase) {
|
|
134
|
+
return { passes: false, reason: 'Content contains generic/advisory phrasing' };
|
|
135
|
+
}
|
|
136
|
+
const hasFluff = FLUFF_PATTERNS.some(r => r.test(content));
|
|
137
|
+
if (hasFluff) {
|
|
138
|
+
return { passes: false, reason: 'Content is too generic — add specific details (file paths, function names, concrete decisions)' };
|
|
139
|
+
}
|
|
140
|
+
if (countSpecificityMarkers(content) < 2) {
|
|
141
|
+
return { passes: false, reason: 'Content lacks specificity — include at least 2 of: file paths, function names, code refs, concrete decisions, or rationale' };
|
|
142
|
+
}
|
|
143
|
+
return { passes: true };
|
|
144
|
+
}
|
|
145
|
+
// ============================================================
|
|
146
|
+
// Light Gate — Life Import bulk ingestion
|
|
147
|
+
// ============================================================
|
|
148
|
+
export function passesLightGate(content) {
|
|
149
|
+
if (content.length < 20) {
|
|
150
|
+
return { passes: false, reason: 'Content too short (min 20 chars)' };
|
|
151
|
+
}
|
|
152
|
+
const hasBannedPhrase = BANNED_PHRASES.some(r => r.test(content));
|
|
153
|
+
if (hasBannedPhrase) {
|
|
154
|
+
return { passes: false, reason: 'Content contains generic/advisory phrasing' };
|
|
155
|
+
}
|
|
156
|
+
return { passes: true };
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=quality-gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quality-gate.js","sourceRoot":"","sources":["../../src/lib/quality-gate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quality Gate v2 — Verification Script
|
|
3
|
+
*
|
|
4
|
+
* Tests MUST PASS and MUST FAIL cases from [[MCP Redesign -- Quality Gate v2]] ADR.
|
|
5
|
+
* Run: npx ts-node packages/memory/src/lib/quality-gate.test.ts
|
|
6
|
+
*/
|
|
7
|
+
import { passesIngestionGate, passesLightGate, passesQualityGate } from './quality-gate.js';
|
|
8
|
+
let passed = 0;
|
|
9
|
+
let failed = 0;
|
|
10
|
+
function assert(label, actual, expected) {
|
|
11
|
+
if (actual === expected) {
|
|
12
|
+
console.log(` PASS ${label}`);
|
|
13
|
+
passed++;
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
console.log(` FAIL ${label} (got ${actual}, expected ${expected})`);
|
|
17
|
+
failed++;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
// ============================================================
|
|
21
|
+
// Ingestion Gate — MUST PASS
|
|
22
|
+
// ============================================================
|
|
23
|
+
console.log('\n--- Ingestion Gate: MUST PASS ---');
|
|
24
|
+
assert('Personal health: "Sean\'s blood type is O+ and he discovered this at age 28"', passesIngestionGate("Sean's blood type is O+ and he discovered this at age 28").passes, true);
|
|
25
|
+
assert('Work fact with numbers: "The deadline for Q2 sprint is March 30"', passesIngestionGate('The deadline for Q2 sprint is March 30').passes, true);
|
|
26
|
+
assert('Health discovery: "Discovered that BMI above 25 increases risk"', passesIngestionGate('Discovered that BMI above 25 increases risk').passes, true);
|
|
27
|
+
assert('API error: "The API returns 429 when rate-limited"', passesIngestionGate('The API returns 429 when rate-limited').passes, true);
|
|
28
|
+
assert('Finance decision: "Sean decided to invest in AAPL instead of GOOG"', passesIngestionGate('Sean decided to invest in AAPL instead of GOOG').passes, true);
|
|
29
|
+
assert('Finance numbers: "Portfolio target is 60% stocks, 40% bonds"', passesIngestionGate('Portfolio target is 60% stocks, 40% bonds').passes, true);
|
|
30
|
+
assert('Dev content still passes: "The `searchMemories` function in src/lib/memory.ts handles vector search"', passesIngestionGate('The `searchMemories` function in src/lib/memory.ts handles vector search').passes, true);
|
|
31
|
+
assert('Preference with reasoning: "Sean prefers TypeScript because it catches errors at compile time"', passesIngestionGate('Sean prefers TypeScript because it catches errors at compile time').passes, true);
|
|
32
|
+
// ============================================================
|
|
33
|
+
// Ingestion Gate — MUST FAIL
|
|
34
|
+
// ============================================================
|
|
35
|
+
console.log('\n--- Ingestion Gate: MUST FAIL ---');
|
|
36
|
+
assert('Banned: "Remember to always be careful"', passesIngestionGate('Remember to always be careful').passes, false);
|
|
37
|
+
assert('Banned: "This is a best practice for clean code"', passesIngestionGate('This is a best practice for clean code').passes, false);
|
|
38
|
+
assert('Too short: "ok"', passesIngestionGate('ok').passes, false);
|
|
39
|
+
assert('No markers: "I did some stuff today and it was interesting overall"', passesIngestionGate('I did some stuff today and it was interesting overall').passes, false);
|
|
40
|
+
assert('Fluff: "The approach demonstrates a preference for clean architecture"', passesIngestionGate('The approach demonstrates a preference for clean architecture').passes, false);
|
|
41
|
+
// ============================================================
|
|
42
|
+
// Light Gate — MUST PASS
|
|
43
|
+
// ============================================================
|
|
44
|
+
console.log('\n--- Light Gate: MUST PASS ---');
|
|
45
|
+
assert('Casual content: "I had pasta for dinner last night"', passesLightGate('I had pasta for dinner last night').passes, true);
|
|
46
|
+
assert('Short but valid: "This is a valid memory entry"', passesLightGate('This is a valid memory entry').passes, true);
|
|
47
|
+
// ============================================================
|
|
48
|
+
// Light Gate — MUST FAIL
|
|
49
|
+
// ============================================================
|
|
50
|
+
console.log('\n--- Light Gate: MUST FAIL ---');
|
|
51
|
+
assert('Too short: "hi"', passesLightGate('hi').passes, false);
|
|
52
|
+
assert('Banned phrase: "Remember to always be careful with authentication"', passesLightGate('Remember to always be careful with authentication').passes, false);
|
|
53
|
+
// ============================================================
|
|
54
|
+
// Strict Gate — spot checks
|
|
55
|
+
// ============================================================
|
|
56
|
+
console.log('\n--- Strict Gate: spot checks ---');
|
|
57
|
+
assert('High confidence dev content passes strict', passesQualityGate({
|
|
58
|
+
content: 'The `searchMemories` function in packages/memory/src/lib/memory.ts uses a cosine similarity threshold of 0.35 because lower values return too much noise',
|
|
59
|
+
confidence: 0.9
|
|
60
|
+
}), true);
|
|
61
|
+
assert('Low confidence rejected', passesQualityGate({ content: 'Some important learning about code', confidence: 0.5 }), false);
|
|
62
|
+
assert('Short content rejected', passesQualityGate({ content: 'Short', confidence: 0.9 }), false);
|
|
63
|
+
// ============================================================
|
|
64
|
+
// Summary
|
|
65
|
+
// ============================================================
|
|
66
|
+
console.log(`\n${'='.repeat(50)}`);
|
|
67
|
+
console.log(`Results: ${passed} passed, ${failed} failed`);
|
|
68
|
+
if (failed > 0) {
|
|
69
|
+
console.log('QUALITY GATE TESTS FAILED');
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
console.log('All quality gate tests passed!');
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=quality-gate.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quality-gate.test.js","sourceRoot":"","sources":["../../src/lib/quality-gate.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cohere Rerank Integration
|
|
3
|
+
*
|
|
4
|
+
* Optional final retrieval stage. Takes RRF-fused candidates + query,
|
|
5
|
+
* returns reranked results with 0-1 relevance scores.
|
|
6
|
+
* Graceful degradation: returns null if COHERE_API_KEY not set or on any error.
|
|
7
|
+
*/
|
|
8
|
+
export interface RerankResult {
|
|
9
|
+
id: string;
|
|
10
|
+
relevanceScore: number;
|
|
11
|
+
index: number;
|
|
12
|
+
}
|
|
13
|
+
export interface RerankDocument {
|
|
14
|
+
id: string;
|
|
15
|
+
content: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Rerank documents using Cohere Rerank v3.5.
|
|
19
|
+
* Returns null if COHERE_API_KEY is not set or on any error.
|
|
20
|
+
* Caller should fall back to existing RRF scores.
|
|
21
|
+
*/
|
|
22
|
+
export declare function cohereRerank(query: string, documents: RerankDocument[], topN?: number): Promise<RerankResult[] | null>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cohere Rerank Integration
|
|
3
|
+
*
|
|
4
|
+
* Optional final retrieval stage. Takes RRF-fused candidates + query,
|
|
5
|
+
* returns reranked results with 0-1 relevance scores.
|
|
6
|
+
* Graceful degradation: returns null if COHERE_API_KEY not set or on any error.
|
|
7
|
+
*/
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// State
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
let missingKeyLogged = false;
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// Cohere Rerank
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
/**
|
|
16
|
+
* Rerank documents using Cohere Rerank v3.5.
|
|
17
|
+
* Returns null if COHERE_API_KEY is not set or on any error.
|
|
18
|
+
* Caller should fall back to existing RRF scores.
|
|
19
|
+
*/
|
|
20
|
+
export async function cohereRerank(query, documents, topN = 20) {
|
|
21
|
+
const apiKey = process.env.COHERE_API_KEY;
|
|
22
|
+
if (!apiKey) {
|
|
23
|
+
if (!missingKeyLogged) {
|
|
24
|
+
console.info('[rerank] COHERE_API_KEY not set — skipping rerank, using RRF scores');
|
|
25
|
+
missingKeyLogged = true;
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
if (documents.length === 0)
|
|
30
|
+
return null;
|
|
31
|
+
try {
|
|
32
|
+
const response = await fetch('https://api.cohere.com/v2/rerank', {
|
|
33
|
+
method: 'POST',
|
|
34
|
+
headers: {
|
|
35
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
36
|
+
'Content-Type': 'application/json',
|
|
37
|
+
},
|
|
38
|
+
body: JSON.stringify({
|
|
39
|
+
model: 'rerank-v3.5',
|
|
40
|
+
query,
|
|
41
|
+
documents: documents.map((d) => d.content),
|
|
42
|
+
top_n: Math.min(topN, documents.length),
|
|
43
|
+
}),
|
|
44
|
+
});
|
|
45
|
+
if (!response.ok) {
|
|
46
|
+
console.warn(`[rerank] Cohere API error: ${response.status} ${response.statusText}`);
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
const data = await response.json();
|
|
50
|
+
return (data.results || []).map((r) => ({
|
|
51
|
+
id: documents[r.index].id,
|
|
52
|
+
relevanceScore: r.relevance_score,
|
|
53
|
+
index: r.index,
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
console.warn('[rerank] Cohere rerank failed:', err instanceof Error ? err.message : err);
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=rerank.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rerank.js","sourceRoot":"","sources":["../../src/lib/rerank.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAiBH,8EAA8E;AAC9E,QAAQ;AACR,8EAA8E;AAE9E,IAAI,gBAAgB,GAAG,KAAK,CAAA;AAE5B,8EAA8E;AAC9E,gBAAgB;AAChB,8EAA8E;AAE9E;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,KAAa,EACb,SAA2B,EAC3B,OAAe,EAAE;IAEjB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAA;IACzC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACtB,OAAO,CAAC,IAAI,CAAC,qEAAqE,CAAC,CAAA;YACnF,gBAAgB,GAAG,IAAI,CAAA;QACzB,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IAED,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IAEvC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,kCAAkC,EAAE;YAC/D,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,eAAe,EAAE,UAAU,MAAM,EAAE;gBACnC,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK,EAAE,aAAa;gBACpB,KAAK;gBACL,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;gBAC1C,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC;aACxC,CAAC;SACH,CAAC,CAAA;QAEF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,OAAO,CAAC,IAAI,CAAC,8BAA8B,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAA;YACpF,OAAO,IAAI,CAAA;QACb,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAE/B,CAAA;QAED,OAAO,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACtC,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE;YACzB,cAAc,EAAE,CAAC,CAAC,eAAe;YACjC,KAAK,EAAE,CAAC,CAAC,KAAK;SACf,CAAC,CAAC,CAAA;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,gCAAgC,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;QACxF,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-Strategy Retrieval + RRF Fusion
|
|
3
|
+
*
|
|
4
|
+
* SearchOrchestrator for Memory Engine v2.
|
|
5
|
+
* Combines semantic, BM25, temporal, and graph search via
|
|
6
|
+
* Reciprocal Rank Fusion. Replaces single-strategy semantic search.
|
|
7
|
+
*/
|
|
8
|
+
import { SupabaseVectorProvider } from '../vectordb/supabase.js';
|
|
9
|
+
import type { MemorySearchResult, SearchOptions } from '../vectordb/types.js';
|
|
10
|
+
export type SearchStrategy = 'semantic' | 'bm25' | 'temporal' | 'graph';
|
|
11
|
+
export interface StrategyResult {
|
|
12
|
+
strategy: string;
|
|
13
|
+
items: {
|
|
14
|
+
id: string;
|
|
15
|
+
rank: number;
|
|
16
|
+
}[];
|
|
17
|
+
}
|
|
18
|
+
export interface FusedItem {
|
|
19
|
+
id: string;
|
|
20
|
+
rrfScore: number;
|
|
21
|
+
normalizedScore: number;
|
|
22
|
+
strategies: string[];
|
|
23
|
+
}
|
|
24
|
+
export interface DetectedStrategies {
|
|
25
|
+
strategies: SearchStrategy[];
|
|
26
|
+
temporalRange?: {
|
|
27
|
+
start: Date;
|
|
28
|
+
end: Date;
|
|
29
|
+
};
|
|
30
|
+
graphSeedIds?: string[];
|
|
31
|
+
}
|
|
32
|
+
export interface SearchV2Options extends SearchOptions {
|
|
33
|
+
entityIds?: string[];
|
|
34
|
+
strategies?: SearchStrategy[];
|
|
35
|
+
rrfK?: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Fuse ranked results from multiple search strategies via RRF.
|
|
39
|
+
*
|
|
40
|
+
* For each item across all strategies: score += 1/(k + rank)
|
|
41
|
+
* Items appearing in multiple strategies accumulate higher scores.
|
|
42
|
+
*
|
|
43
|
+
* @param strategyResults - Ranked results from each strategy
|
|
44
|
+
* @param k - RRF constant (default 60, standard in literature)
|
|
45
|
+
* @param topN - Max results to return
|
|
46
|
+
*/
|
|
47
|
+
export declare function reciprocalRankFusion(strategyResults: StrategyResult[], k?: number, topN?: number): FusedItem[];
|
|
48
|
+
/**
|
|
49
|
+
* Detect which search strategies should be activated for a query.
|
|
50
|
+
* Semantic + BM25 always run. Temporal activates on date patterns.
|
|
51
|
+
* Graph activates when entity seed IDs are provided.
|
|
52
|
+
*/
|
|
53
|
+
export declare function detectStrategies(query: string, entityIds?: string[]): DetectedStrategies;
|
|
54
|
+
/**
|
|
55
|
+
* Parse temporal references in a query to a date range.
|
|
56
|
+
* Falls back to 30-day lookback for ambiguous patterns.
|
|
57
|
+
*/
|
|
58
|
+
export declare function parseTemporalRange(query: string): {
|
|
59
|
+
start: Date;
|
|
60
|
+
end: Date;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Find known entities mentioned in a search query.
|
|
64
|
+
* Tokenizes the query, filters stopwords, looks up against memory_entities.
|
|
65
|
+
* Returns entity IDs for graph search activation.
|
|
66
|
+
*/
|
|
67
|
+
export declare function findEntitiesInQuery(query: string, provider: SupabaseVectorProvider): Promise<string[]>;
|
|
68
|
+
/**
|
|
69
|
+
* Multi-strategy search with RRF fusion.
|
|
70
|
+
*
|
|
71
|
+
* Runs semantic + BM25 in parallel (always), plus temporal and graph
|
|
72
|
+
* when detected. Fuses results via Reciprocal Rank Fusion.
|
|
73
|
+
* Returns MemorySearchResult[] for backward compatibility.
|
|
74
|
+
*/
|
|
75
|
+
export declare function searchMemoriesV2(query: string, options?: SearchV2Options): Promise<MemorySearchResult[]>;
|