@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.
Files changed (156) hide show
  1. package/README.md +135 -0
  2. package/dist/index.d.ts +34 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +38 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/lib/auth.d.ts +18 -0
  7. package/dist/lib/auth.d.ts.map +1 -0
  8. package/dist/lib/auth.js +31 -0
  9. package/dist/lib/auth.js.map +1 -0
  10. package/dist/lib/auto-derive.d.ts +35 -0
  11. package/dist/lib/auto-derive.js +261 -0
  12. package/dist/lib/auto-derive.js.map +1 -0
  13. package/dist/lib/borderline.d.ts +26 -0
  14. package/dist/lib/borderline.js +121 -0
  15. package/dist/lib/borderline.js.map +1 -0
  16. package/dist/lib/client.d.ts +28 -0
  17. package/dist/lib/client.d.ts.map +1 -0
  18. package/dist/lib/client.js +60 -0
  19. package/dist/lib/client.js.map +1 -0
  20. package/dist/lib/context.d.ts +38 -0
  21. package/dist/lib/context.d.ts.map +1 -0
  22. package/dist/lib/context.js +334 -0
  23. package/dist/lib/context.js.map +1 -0
  24. package/dist/lib/embeddings.d.ts +60 -0
  25. package/dist/lib/embeddings.d.ts.map +1 -0
  26. package/dist/lib/embeddings.js +229 -0
  27. package/dist/lib/embeddings.js.map +1 -0
  28. package/dist/lib/entity-pipeline.d.ts +23 -0
  29. package/dist/lib/entity-pipeline.js +151 -0
  30. package/dist/lib/entity-pipeline.js.map +1 -0
  31. package/dist/lib/formatting.d.ts +13 -0
  32. package/dist/lib/formatting.d.ts.map +1 -0
  33. package/dist/lib/formatting.js +60 -0
  34. package/dist/lib/formatting.js.map +1 -0
  35. package/dist/lib/learning-extractor.d.ts +144 -0
  36. package/dist/lib/learning-extractor.d.ts.map +1 -0
  37. package/dist/lib/learning-extractor.js +921 -0
  38. package/dist/lib/learning-extractor.js.map +1 -0
  39. package/dist/lib/lifecycle.d.ts +45 -0
  40. package/dist/lib/lifecycle.js +84 -0
  41. package/dist/lib/lifecycle.js.map +1 -0
  42. package/dist/lib/memory.d.ts +128 -0
  43. package/dist/lib/memory.d.ts.map +1 -0
  44. package/dist/lib/memory.js +590 -0
  45. package/dist/lib/memory.js.map +1 -0
  46. package/dist/lib/quality-gate.d.ts +32 -0
  47. package/dist/lib/quality-gate.js +158 -0
  48. package/dist/lib/quality-gate.js.map +1 -0
  49. package/dist/lib/quality-gate.test.d.ts +7 -0
  50. package/dist/lib/quality-gate.test.js +75 -0
  51. package/dist/lib/quality-gate.test.js.map +1 -0
  52. package/dist/lib/rerank.d.ts +22 -0
  53. package/dist/lib/rerank.js +61 -0
  54. package/dist/lib/rerank.js.map +1 -0
  55. package/dist/lib/retrieval.d.ts +75 -0
  56. package/dist/lib/retrieval.js +380 -0
  57. package/dist/lib/retrieval.js.map +1 -0
  58. package/dist/migrate.d.ts +17 -0
  59. package/dist/migrate.d.ts.map +1 -0
  60. package/dist/migrate.js +81 -0
  61. package/dist/migrate.js.map +1 -0
  62. package/dist/routes/analyze-codebase.d.ts +9 -0
  63. package/dist/routes/analyze-codebase.d.ts.map +1 -0
  64. package/dist/routes/analyze-codebase.js +70 -0
  65. package/dist/routes/analyze-codebase.js.map +1 -0
  66. package/dist/routes/analyze-voice.d.ts +9 -0
  67. package/dist/routes/analyze-voice.d.ts.map +1 -0
  68. package/dist/routes/analyze-voice.js +63 -0
  69. package/dist/routes/analyze-voice.js.map +1 -0
  70. package/dist/routes/assemble-context.d.ts +9 -0
  71. package/dist/routes/assemble-context.d.ts.map +1 -0
  72. package/dist/routes/assemble-context.js +68 -0
  73. package/dist/routes/assemble-context.js.map +1 -0
  74. package/dist/routes/bootstrap.d.ts +12 -0
  75. package/dist/routes/bootstrap.d.ts.map +1 -0
  76. package/dist/routes/bootstrap.js +102 -0
  77. package/dist/routes/bootstrap.js.map +1 -0
  78. package/dist/routes/browse.d.ts +11 -0
  79. package/dist/routes/browse.js +85 -0
  80. package/dist/routes/browse.js.map +1 -0
  81. package/dist/routes/capture-thought.d.ts +13 -0
  82. package/dist/routes/capture-thought.d.ts.map +1 -0
  83. package/dist/routes/capture-thought.js +178 -0
  84. package/dist/routes/capture-thought.js.map +1 -0
  85. package/dist/routes/capture.d.ts +13 -0
  86. package/dist/routes/capture.d.ts.map +1 -0
  87. package/dist/routes/capture.js +86 -0
  88. package/dist/routes/capture.js.map +1 -0
  89. package/dist/routes/cite.d.ts +9 -0
  90. package/dist/routes/cite.d.ts.map +1 -0
  91. package/dist/routes/cite.js +49 -0
  92. package/dist/routes/cite.js.map +1 -0
  93. package/dist/routes/crud.d.ts +11 -0
  94. package/dist/routes/crud.d.ts.map +1 -0
  95. package/dist/routes/crud.js +176 -0
  96. package/dist/routes/crud.js.map +1 -0
  97. package/dist/routes/dashboard.d.ts +9 -0
  98. package/dist/routes/dashboard.d.ts.map +1 -0
  99. package/dist/routes/dashboard.js +85 -0
  100. package/dist/routes/dashboard.js.map +1 -0
  101. package/dist/routes/entity-cron.d.ts +8 -0
  102. package/dist/routes/entity-cron.js +31 -0
  103. package/dist/routes/entity-cron.js.map +1 -0
  104. package/dist/routes/export.d.ts +8 -0
  105. package/dist/routes/export.d.ts.map +1 -0
  106. package/dist/routes/export.js +69 -0
  107. package/dist/routes/export.js.map +1 -0
  108. package/dist/routes/extract-pr-learnings.d.ts +12 -0
  109. package/dist/routes/extract-pr-learnings.d.ts.map +1 -0
  110. package/dist/routes/extract-pr-learnings.js +127 -0
  111. package/dist/routes/extract-pr-learnings.js.map +1 -0
  112. package/dist/routes/forget-cron.d.ts +9 -0
  113. package/dist/routes/forget-cron.js +30 -0
  114. package/dist/routes/forget-cron.js.map +1 -0
  115. package/dist/routes/learnings.d.ts +9 -0
  116. package/dist/routes/learnings.d.ts.map +1 -0
  117. package/dist/routes/learnings.js +237 -0
  118. package/dist/routes/learnings.js.map +1 -0
  119. package/dist/routes/pulse.d.ts +9 -0
  120. package/dist/routes/pulse.d.ts.map +1 -0
  121. package/dist/routes/pulse.js +133 -0
  122. package/dist/routes/pulse.js.map +1 -0
  123. package/dist/routes/search.d.ts +8 -0
  124. package/dist/routes/search.d.ts.map +1 -0
  125. package/dist/routes/search.js +107 -0
  126. package/dist/routes/search.js.map +1 -0
  127. package/dist/routes/store.d.ts +8 -0
  128. package/dist/routes/store.d.ts.map +1 -0
  129. package/dist/routes/store.js +89 -0
  130. package/dist/routes/store.js.map +1 -0
  131. package/dist/routes/sync.d.ts +12 -0
  132. package/dist/routes/sync.d.ts.map +1 -0
  133. package/dist/routes/sync.js +83 -0
  134. package/dist/routes/sync.js.map +1 -0
  135. package/dist/routes/voice-profile.d.ts +9 -0
  136. package/dist/routes/voice-profile.d.ts.map +1 -0
  137. package/dist/routes/voice-profile.js +124 -0
  138. package/dist/routes/voice-profile.js.map +1 -0
  139. package/dist/server.d.ts +37 -0
  140. package/dist/server.d.ts.map +1 -0
  141. package/dist/server.js +99 -0
  142. package/dist/server.js.map +1 -0
  143. package/dist/vectordb/index.d.ts +17 -0
  144. package/dist/vectordb/index.d.ts.map +1 -0
  145. package/dist/vectordb/index.js +39 -0
  146. package/dist/vectordb/index.js.map +1 -0
  147. package/dist/vectordb/supabase.d.ts +62 -0
  148. package/dist/vectordb/supabase.d.ts.map +1 -0
  149. package/dist/vectordb/supabase.js +711 -0
  150. package/dist/vectordb/supabase.js.map +1 -0
  151. package/dist/vectordb/types.d.ts +217 -0
  152. package/dist/vectordb/types.d.ts.map +1 -0
  153. package/dist/vectordb/types.js +28 -0
  154. package/dist/vectordb/types.js.map +1 -0
  155. package/package.json +49 -0
  156. package/setup.sql +1037 -0
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Embeddings Utility
3
+ *
4
+ * Generates vector embeddings using configurable provider.
5
+ * Supports OpenAI text-embedding-3-small and Google Gemini Embedding 2.
6
+ * Set EMBEDDING_PROVIDER env var: 'openai' (default) or 'gemini'.
7
+ */
8
+ export declare const EMBEDDING_CONFIG: {
9
+ readonly MODEL: "gemini-embedding-001" | "text-embedding-3-small";
10
+ readonly MODEL_VERSION: "v1";
11
+ readonly DIMENSIONS: 1536;
12
+ readonly PROVIDER: string;
13
+ readonly MAX_TOKENS: 8191;
14
+ };
15
+ export interface EmbeddingResult {
16
+ embedding: number[];
17
+ model: string;
18
+ modelVersion: string;
19
+ dimensions: number;
20
+ usage: {
21
+ promptTokens: number;
22
+ totalTokens: number;
23
+ };
24
+ }
25
+ /**
26
+ * Generate embedding for a single text (provider-agnostic)
27
+ */
28
+ export declare function generateEmbedding(text: string): Promise<EmbeddingResult>;
29
+ /**
30
+ * Generate embeddings for multiple texts in batch
31
+ */
32
+ export declare function generateEmbeddingsBatch(texts: string[]): Promise<EmbeddingResult[]>;
33
+ /**
34
+ * Calculate cosine similarity between two embeddings
35
+ */
36
+ export declare function cosineSimilarity(a: number[], b: number[]): number;
37
+ /**
38
+ * Format embedding for Supabase pgvector storage
39
+ */
40
+ export declare function formatEmbeddingForPgVector(embedding: number[]): string;
41
+ /**
42
+ * Parse pgvector format back to number array
43
+ */
44
+ export declare function parseEmbeddingFromPgVector(pgvectorString: string): number[];
45
+ /**
46
+ * Check if embeddings need regeneration
47
+ */
48
+ export declare function needsReembedding(currentModel: string, currentVersion: string): boolean;
49
+ export interface EmbeddingHealthStatus {
50
+ status: 'healthy' | 'degraded' | 'failed';
51
+ canStore: boolean;
52
+ canSearch: boolean;
53
+ reason?: string;
54
+ latencyMs?: number;
55
+ quotaExceeded?: boolean;
56
+ }
57
+ /**
58
+ * Check embedding service health
59
+ */
60
+ export declare function checkEmbeddingHealth(): Promise<EmbeddingHealthStatus>;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embeddings.d.ts","sourceRoot":"","sources":["../../src/lib/embeddings.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,eAAO,MAAM,gBAAgB;;;;;;CAMnB,CAAA;AAEV,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE;QACL,YAAY,EAAE,MAAM,CAAA;QACpB,WAAW,EAAE,MAAM,CAAA;KACpB,CAAA;CACF;AAqBD;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAwB9E;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAwBzF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAmBjE;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,CAEtE;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,EAAE,CAS3E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,MAAM,EACpB,cAAc,EAAE,MAAM,GACrB,OAAO,CAKT;AAID,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,QAAQ,CAAA;IACzC,QAAQ,EAAE,OAAO,CAAA;IACjB,SAAS,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAED;;GAEG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,qBAAqB,CAAC,CA2E3E"}
@@ -0,0 +1,229 @@
1
+ /**
2
+ * Embeddings Utility
3
+ *
4
+ * Generates vector embeddings using configurable provider.
5
+ * Supports OpenAI text-embedding-3-small and Google Gemini Embedding 2.
6
+ * Set EMBEDDING_PROVIDER env var: 'openai' (default) or 'gemini'.
7
+ */
8
+ import OpenAI from 'openai';
9
+ // Embedding provider detection
10
+ const EMBEDDING_PROVIDER = process.env.EMBEDDING_PROVIDER || 'openai';
11
+ // Embedding model configuration
12
+ export const EMBEDDING_CONFIG = {
13
+ MODEL: EMBEDDING_PROVIDER === 'gemini' ? 'gemini-embedding-001' : 'text-embedding-3-small',
14
+ MODEL_VERSION: 'v1',
15
+ DIMENSIONS: 1536,
16
+ PROVIDER: EMBEDDING_PROVIDER,
17
+ MAX_TOKENS: 8191,
18
+ };
19
+ // Singleton OpenAI client
20
+ let openaiClient = null;
21
+ function getOpenAIClient() {
22
+ if (openaiClient)
23
+ return openaiClient;
24
+ const apiKey = process.env.OPENAI_API_KEY;
25
+ if (!apiKey) {
26
+ throw new Error('OPENAI_API_KEY environment variable is not set. ' +
27
+ 'Get your API key from https://platform.openai.com/api-keys');
28
+ }
29
+ openaiClient = new OpenAI({ apiKey });
30
+ return openaiClient;
31
+ }
32
+ /**
33
+ * Generate embedding for a single text (provider-agnostic)
34
+ */
35
+ export async function generateEmbedding(text) {
36
+ if (EMBEDDING_PROVIDER === 'gemini') {
37
+ return generateGeminiEmbedding(text);
38
+ }
39
+ return generateOpenAIEmbedding(text);
40
+ }
41
+ async function generateOpenAIEmbedding(text) {
42
+ const client = getOpenAIClient();
43
+ const maxChars = EMBEDDING_CONFIG.MAX_TOKENS * 4;
44
+ const truncatedText = text.slice(0, maxChars);
45
+ const response = await client.embeddings.create({
46
+ model: 'text-embedding-3-small',
47
+ input: truncatedText,
48
+ encoding_format: 'float',
49
+ });
50
+ const embeddingData = response.data[0];
51
+ return {
52
+ embedding: embeddingData.embedding,
53
+ model: 'openai/text-embedding-3-small',
54
+ modelVersion: 'v1',
55
+ dimensions: EMBEDDING_CONFIG.DIMENSIONS,
56
+ usage: {
57
+ promptTokens: response.usage.prompt_tokens,
58
+ totalTokens: response.usage.total_tokens,
59
+ },
60
+ };
61
+ }
62
+ async function generateGeminiEmbedding(text) {
63
+ const apiKey = process.env.GOOGLE_API_KEY;
64
+ if (!apiKey) {
65
+ throw new Error('GOOGLE_API_KEY not set. Required when EMBEDDING_PROVIDER=gemini.');
66
+ }
67
+ const maxChars = EMBEDDING_CONFIG.MAX_TOKENS * 4;
68
+ const truncatedText = text.slice(0, maxChars);
69
+ const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/gemini-embedding-001:embedContent?key=${apiKey}`, {
70
+ method: 'POST',
71
+ headers: { 'Content-Type': 'application/json' },
72
+ body: JSON.stringify({
73
+ model: 'models/gemini-embedding-001',
74
+ content: { parts: [{ text: truncatedText }] },
75
+ outputDimensionality: EMBEDDING_CONFIG.DIMENSIONS,
76
+ }),
77
+ });
78
+ if (!response.ok) {
79
+ throw new Error(`Gemini embedding failed: ${response.status} ${response.statusText}`);
80
+ }
81
+ const data = await response.json();
82
+ return {
83
+ embedding: data.embedding.values,
84
+ model: 'gemini/gemini-embedding-001',
85
+ modelVersion: 'v1',
86
+ dimensions: data.embedding.values.length,
87
+ usage: { promptTokens: 0, totalTokens: 0 }, // Gemini doesn't report token usage
88
+ };
89
+ }
90
+ /**
91
+ * Generate embeddings for multiple texts in batch
92
+ */
93
+ export async function generateEmbeddingsBatch(texts) {
94
+ if (texts.length === 0)
95
+ return [];
96
+ const client = getOpenAIClient();
97
+ const maxChars = EMBEDDING_CONFIG.MAX_TOKENS * 4;
98
+ const truncatedTexts = texts.map(t => t.slice(0, maxChars));
99
+ const response = await client.embeddings.create({
100
+ model: EMBEDDING_CONFIG.MODEL,
101
+ input: truncatedTexts,
102
+ encoding_format: 'float',
103
+ });
104
+ return response.data.map((embeddingData) => ({
105
+ embedding: embeddingData.embedding,
106
+ model: `${EMBEDDING_CONFIG.PROVIDER}/${EMBEDDING_CONFIG.MODEL}`,
107
+ modelVersion: EMBEDDING_CONFIG.MODEL_VERSION,
108
+ dimensions: EMBEDDING_CONFIG.DIMENSIONS,
109
+ usage: {
110
+ promptTokens: Math.floor(response.usage.prompt_tokens / texts.length),
111
+ totalTokens: Math.floor(response.usage.total_tokens / texts.length),
112
+ },
113
+ }));
114
+ }
115
+ /**
116
+ * Calculate cosine similarity between two embeddings
117
+ */
118
+ export function cosineSimilarity(a, b) {
119
+ if (a.length !== b.length) {
120
+ throw new Error(`Embedding dimensions don't match: ${a.length} vs ${b.length}`);
121
+ }
122
+ let dotProduct = 0;
123
+ let normA = 0;
124
+ let normB = 0;
125
+ for (let i = 0; i < a.length; i++) {
126
+ dotProduct += a[i] * b[i];
127
+ normA += a[i] * a[i];
128
+ normB += b[i] * b[i];
129
+ }
130
+ const magnitude = Math.sqrt(normA) * Math.sqrt(normB);
131
+ if (magnitude === 0)
132
+ return 0;
133
+ return dotProduct / magnitude;
134
+ }
135
+ /**
136
+ * Format embedding for Supabase pgvector storage
137
+ */
138
+ export function formatEmbeddingForPgVector(embedding) {
139
+ return `[${embedding.join(',')}]`;
140
+ }
141
+ /**
142
+ * Parse pgvector format back to number array
143
+ */
144
+ export function parseEmbeddingFromPgVector(pgvectorString) {
145
+ if (!pgvectorString)
146
+ return [];
147
+ if (Array.isArray(pgvectorString)) {
148
+ return pgvectorString.map(Number);
149
+ }
150
+ const cleaned = pgvectorString.replace(/^\[|\]$/g, '');
151
+ return cleaned.split(',').map(Number);
152
+ }
153
+ /**
154
+ * Check if embeddings need regeneration
155
+ */
156
+ export function needsReembedding(currentModel, currentVersion) {
157
+ const expectedModel = `${EMBEDDING_CONFIG.PROVIDER}/${EMBEDDING_CONFIG.MODEL}`;
158
+ const expectedVersion = EMBEDDING_CONFIG.MODEL_VERSION;
159
+ return currentModel !== expectedModel || currentVersion !== expectedVersion;
160
+ }
161
+ /**
162
+ * Check embedding service health
163
+ */
164
+ export async function checkEmbeddingHealth() {
165
+ const startTime = Date.now();
166
+ try {
167
+ const client = getOpenAIClient();
168
+ const response = await client.embeddings.create({
169
+ model: EMBEDDING_CONFIG.MODEL,
170
+ input: 'health check',
171
+ encoding_format: 'float',
172
+ });
173
+ const latencyMs = Date.now() - startTime;
174
+ if (!response.data?.[0]?.embedding) {
175
+ return {
176
+ status: 'degraded',
177
+ canStore: false,
178
+ canSearch: false,
179
+ reason: 'OpenAI returned empty embedding',
180
+ latencyMs,
181
+ };
182
+ }
183
+ return {
184
+ status: 'healthy',
185
+ canStore: true,
186
+ canSearch: true,
187
+ latencyMs,
188
+ };
189
+ }
190
+ catch (error) {
191
+ const latencyMs = Date.now() - startTime;
192
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
193
+ const isQuotaExceeded = errorMessage.includes('quota') ||
194
+ errorMessage.includes('rate limit') ||
195
+ errorMessage.includes('exceeded') ||
196
+ errorMessage.includes('billing') ||
197
+ errorMessage.includes('insufficient_quota');
198
+ const isAuthError = errorMessage.includes('API key') ||
199
+ errorMessage.includes('authentication') ||
200
+ errorMessage.includes('unauthorized');
201
+ if (isQuotaExceeded) {
202
+ return {
203
+ status: 'degraded',
204
+ canStore: false,
205
+ canSearch: false,
206
+ reason: 'OpenAI quota exceeded - cannot generate embeddings',
207
+ quotaExceeded: true,
208
+ latencyMs,
209
+ };
210
+ }
211
+ if (isAuthError) {
212
+ return {
213
+ status: 'failed',
214
+ canStore: false,
215
+ canSearch: false,
216
+ reason: 'OpenAI API key invalid or missing',
217
+ latencyMs,
218
+ };
219
+ }
220
+ return {
221
+ status: 'failed',
222
+ canStore: false,
223
+ canSearch: false,
224
+ reason: errorMessage,
225
+ latencyMs,
226
+ };
227
+ }
228
+ }
229
+ //# sourceMappingURL=embeddings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embeddings.js","sourceRoot":"","sources":["../../src/lib/embeddings.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Entity Extraction Pipeline
3
+ *
4
+ * Async entity extraction from memory content. Entities earn existence
5
+ * at 3+ mentions. Canonicalized via multi-signal matching:
6
+ * 1. Exact normalized name match (free, instant)
7
+ * 2. ILIKE fuzzy match (free, fast)
8
+ * 3. Embedding similarity >0.85 (requires OPENAI_API_KEY)
9
+ *
10
+ * Graceful degradation: works without OPENAI_API_KEY using name matching only.
11
+ */
12
+ export interface EntityExtractionResult {
13
+ candidates: number;
14
+ created: number;
15
+ merged: number;
16
+ linked: number;
17
+ skipped: number;
18
+ }
19
+ /**
20
+ * Process entity extraction for a stored memory.
21
+ * Designed to run fire-and-forget after memory store completes.
22
+ */
23
+ export declare function processEntitiesForMemory(memoryId: string, content: string, userId: string): Promise<EntityExtractionResult>;
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Entity Extraction Pipeline
3
+ *
4
+ * Async entity extraction from memory content. Entities earn existence
5
+ * at 3+ mentions. Canonicalized via multi-signal matching:
6
+ * 1. Exact normalized name match (free, instant)
7
+ * 2. ILIKE fuzzy match (free, fast)
8
+ * 3. Embedding similarity >0.85 (requires OPENAI_API_KEY)
9
+ *
10
+ * Graceful degradation: works without OPENAI_API_KEY using name matching only.
11
+ */
12
+ import { getVectorDB } from '../vectordb/index.js';
13
+ import { SupabaseVectorProvider } from '../vectordb/supabase.js';
14
+ import { getMemoryClient, getUserId } from './client.js';
15
+ import { extractEntityCandidates } from './auto-derive.js';
16
+ import { generateEmbedding, formatEmbeddingForPgVector } from './embeddings.js';
17
+ // ---------------------------------------------------------------------------
18
+ // Configuration
19
+ // ---------------------------------------------------------------------------
20
+ const MENTION_THRESHOLD = 3;
21
+ const EMBEDDING_SIMILARITY_THRESHOLD = 0.85;
22
+ // ---------------------------------------------------------------------------
23
+ // Core Pipeline
24
+ // ---------------------------------------------------------------------------
25
+ /**
26
+ * Process entity extraction for a stored memory.
27
+ * Designed to run fire-and-forget after memory store completes.
28
+ */
29
+ export async function processEntitiesForMemory(memoryId, content, userId) {
30
+ const db = getVectorDB();
31
+ if (!(db instanceof SupabaseVectorProvider)) {
32
+ return { candidates: 0, created: 0, merged: 0, linked: 0, skipped: 0 };
33
+ }
34
+ const provider = db;
35
+ const result = { candidates: 0, created: 0, merged: 0, linked: 0, skipped: 0 };
36
+ // 1. Extract entity candidates from content
37
+ const candidates = extractEntityCandidates(content);
38
+ result.candidates = candidates.length;
39
+ if (candidates.length === 0)
40
+ return result;
41
+ // 2. Process each candidate
42
+ for (const candidate of candidates) {
43
+ try {
44
+ await processCandidate(provider, candidate, memoryId, userId, result);
45
+ }
46
+ catch (err) {
47
+ console.warn(`[entity] Failed to process candidate "${candidate.name}":`, err instanceof Error ? err.message : err);
48
+ result.skipped++;
49
+ }
50
+ }
51
+ return result;
52
+ }
53
+ // ---------------------------------------------------------------------------
54
+ // Candidate Processing
55
+ // ---------------------------------------------------------------------------
56
+ async function processCandidate(provider, candidate, memoryId, userId, result) {
57
+ const normalizedName = candidate.name.trim();
58
+ const entityType = candidate.type;
59
+ // Step 1: Try to find existing entity via multi-signal matching
60
+ let existingEntity = await matchExistingEntity(provider, normalizedName, entityType);
61
+ if (existingEntity) {
62
+ // Entity exists — increment mentions and link
63
+ await provider.incrementEntityMentions(existingEntity.id);
64
+ await provider.linkMemoryToEntity(memoryId, existingEntity.id, 'mentions');
65
+ result.merged++;
66
+ result.linked++;
67
+ return;
68
+ }
69
+ // Step 2: No existing entity — check mention threshold
70
+ const mentionCount = await countMentions(normalizedName);
71
+ if (mentionCount < MENTION_THRESHOLD) {
72
+ result.skipped++;
73
+ return;
74
+ }
75
+ // Step 3: Create new entity (threshold met, no match found)
76
+ let embeddingStr;
77
+ try {
78
+ // Generate embedding with type context: "React (technology)" not just "React"
79
+ const embeddingResult = await generateEmbedding(`${normalizedName} (${entityType})`);
80
+ embeddingStr = formatEmbeddingForPgVector(embeddingResult.embedding);
81
+ }
82
+ catch {
83
+ // OPENAI_API_KEY missing or embedding failed — create without embedding
84
+ }
85
+ const newEntity = await provider.createEntity({
86
+ name: normalizedName,
87
+ entityType,
88
+ embedding: embeddingStr,
89
+ userId,
90
+ });
91
+ if (newEntity) {
92
+ await provider.linkMemoryToEntity(memoryId, newEntity.id, 'mentions');
93
+ result.created++;
94
+ result.linked++;
95
+ }
96
+ else {
97
+ result.skipped++;
98
+ }
99
+ }
100
+ // ---------------------------------------------------------------------------
101
+ // Multi-Signal Entity Matching
102
+ // ---------------------------------------------------------------------------
103
+ /**
104
+ * Try to match a candidate against existing entities using multiple signals:
105
+ * 1. Exact normalized name + type match
106
+ * 2. ILIKE fuzzy match
107
+ * 3. Embedding similarity (if OPENAI_API_KEY available)
108
+ */
109
+ async function matchExistingEntity(provider, name, entityType) {
110
+ // Signal 1: Exact normalized match (case-insensitive)
111
+ const exactMatch = await provider.findEntityByName(name, entityType);
112
+ if (exactMatch)
113
+ return exactMatch;
114
+ // Signal 2: ILIKE fuzzy match
115
+ const fuzzyMatch = await provider.findEntityByNameFuzzy(name, entityType);
116
+ if (fuzzyMatch)
117
+ return fuzzyMatch;
118
+ // Signal 3: Embedding similarity (only if OPENAI_API_KEY available)
119
+ if (process.env.OPENAI_API_KEY) {
120
+ try {
121
+ const embeddingResult = await generateEmbedding(`${name} (${entityType})`);
122
+ const embeddingStr = formatEmbeddingForPgVector(embeddingResult.embedding);
123
+ const embeddingMatch = await provider.findEntityByEmbedding(embeddingStr, entityType, EMBEDDING_SIMILARITY_THRESHOLD);
124
+ if (embeddingMatch)
125
+ return embeddingMatch;
126
+ }
127
+ catch {
128
+ // Embedding failed — continue without it
129
+ }
130
+ }
131
+ return null;
132
+ }
133
+ // ---------------------------------------------------------------------------
134
+ // Mention Counting
135
+ // ---------------------------------------------------------------------------
136
+ async function countMentions(name) {
137
+ try {
138
+ const client = getMemoryClient();
139
+ const { data, error } = await client.rpc('count_entity_mentions', {
140
+ p_entity_name: name,
141
+ p_user_id: getUserId(),
142
+ });
143
+ if (error)
144
+ return 0;
145
+ return data ?? 0;
146
+ }
147
+ catch {
148
+ return 0;
149
+ }
150
+ }
151
+ //# sourceMappingURL=entity-pipeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entity-pipeline.js","sourceRoot":"","sources":["../../src/lib/entity-pipeline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Memory Formatting - Shared emoji maps and formatting helpers
3
+ *
4
+ * Single source of truth for category/source emoji across the codebase.
5
+ */
6
+ export declare const CATEGORY_EMOJI: Record<string, string>;
7
+ export declare const CATEGORY_EMOJI_SLACK: Record<string, string>;
8
+ export declare const CATEGORY_EMOJI_TEXT: Record<string, string>;
9
+ export declare const SOURCE_TYPE_EMOJI: Record<string, string>;
10
+ /**
11
+ * Get category emoji with fallback for unknown categories
12
+ */
13
+ export declare function getCategoryEmoji(category: string | undefined, style?: 'unicode' | 'slack' | 'text'): string;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatting.d.ts","sourceRoot":"","sources":["../../src/lib/formatting.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAQjD,CAAA;AAGD,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAQvD,CAAA;AAGD,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAQtD,CAAA;AAGD,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAUpD,CAAA;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,KAAK,GAAE,SAAS,GAAG,OAAO,GAAG,MAAkB,GAC9C,MAAM,CAQR"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Memory Formatting - Shared emoji maps and formatting helpers
3
+ *
4
+ * Single source of truth for category/source emoji across the codebase.
5
+ */
6
+ // Category emoji for display (Unicode for UI/terminal contexts)
7
+ export const CATEGORY_EMOJI = {
8
+ gotcha: '\u26a0\ufe0f',
9
+ pattern: '\ud83d\udd04',
10
+ fix: '\ud83d\udd27',
11
+ insight: '\ud83d\udca1',
12
+ question: '\u2753',
13
+ preference: '\ud83c\udfa8',
14
+ convention: '\ud83d\udccf',
15
+ };
16
+ // Slack-compatible category emoji (for Slack message formatting)
17
+ export const CATEGORY_EMOJI_SLACK = {
18
+ gotcha: ':warning:',
19
+ pattern: ':repeat:',
20
+ fix: ':wrench:',
21
+ insight: ':bulb:',
22
+ question: ':grey_question:',
23
+ preference: ':art:',
24
+ convention: ':straight_ruler:',
25
+ };
26
+ // Text-only category markers (for plain text contexts like agent logs)
27
+ export const CATEGORY_EMOJI_TEXT = {
28
+ gotcha: '|!|',
29
+ pattern: '->',
30
+ fix: '[+]',
31
+ insight: '*',
32
+ question: '?',
33
+ preference: '~',
34
+ convention: '#',
35
+ };
36
+ // Source type emoji for visual differentiation
37
+ export const SOURCE_TYPE_EMOJI = {
38
+ pr: '\ud83d\udd00',
39
+ plan: '\ud83d\udccb',
40
+ manual: '\u270d\ufe0f',
41
+ extracted: '\ud83e\udd16',
42
+ bootstrap: '\ud83c\udfd7\ufe0f',
43
+ advisor_session: '\ud83d\udcad',
44
+ web_research: '\ud83c\udf10',
45
+ session: '\ud83d\udcbb',
46
+ codebase_analysis: '\ud83d\udd0d',
47
+ };
48
+ /**
49
+ * Get category emoji with fallback for unknown categories
50
+ */
51
+ export function getCategoryEmoji(category, style = 'unicode') {
52
+ const map = style === 'slack'
53
+ ? CATEGORY_EMOJI_SLACK
54
+ : style === 'text'
55
+ ? CATEGORY_EMOJI_TEXT
56
+ : CATEGORY_EMOJI;
57
+ const fallback = style === 'unicode' ? '\ud83d\udcdd' : style === 'slack' ? ':memo:' : '?';
58
+ return map[category || ''] || fallback;
59
+ }
60
+ //# sourceMappingURL=formatting.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatting.js","sourceRoot":"","sources":["../../src/lib/formatting.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,gEAAgE;AAChE,MAAM,CAAC,MAAM,cAAc,GAA2B;IACpD,MAAM,EAAE,cAAc;IACtB,OAAO,EAAE,cAAc;IACvB,GAAG,EAAE,cAAc;IACnB,OAAO,EAAE,cAAc;IACvB,QAAQ,EAAE,QAAQ;IAClB,UAAU,EAAE,cAAc;IAC1B,UAAU,EAAE,cAAc;CAC3B,CAAA;AAED,iEAAiE;AACjE,MAAM,CAAC,MAAM,oBAAoB,GAA2B;IAC1D,MAAM,EAAE,WAAW;IACnB,OAAO,EAAE,UAAU;IACnB,GAAG,EAAE,UAAU;IACf,OAAO,EAAE,QAAQ;IACjB,QAAQ,EAAE,iBAAiB;IAC3B,UAAU,EAAE,OAAO;IACnB,UAAU,EAAE,kBAAkB;CAC/B,CAAA;AAED,uEAAuE;AACvE,MAAM,CAAC,MAAM,mBAAmB,GAA2B;IACzD,MAAM,EAAE,KAAK;IACb,OAAO,EAAE,IAAI;IACb,GAAG,EAAE,KAAK;IACV,OAAO,EAAE,GAAG;IACZ,QAAQ,EAAE,GAAG;IACb,UAAU,EAAE,GAAG;IACf,UAAU,EAAE,GAAG;CAChB,CAAA;AAED,+CAA+C;AAC/C,MAAM,CAAC,MAAM,iBAAiB,GAA2B;IACvD,EAAE,EAAE,cAAc;IAClB,IAAI,EAAE,cAAc;IACpB,MAAM,EAAE,cAAc;IACtB,SAAS,EAAE,cAAc;IACzB,SAAS,EAAE,oBAAoB;IAC/B,eAAe,EAAE,cAAc;IAC/B,YAAY,EAAE,cAAc;IAC5B,OAAO,EAAE,cAAc;IACvB,iBAAiB,EAAE,cAAc;CAClC,CAAA;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAC9B,QAA4B,EAC5B,QAAsC,SAAS;IAE/C,MAAM,GAAG,GAAG,KAAK,KAAK,OAAO;QAC3B,CAAC,CAAC,oBAAoB;QACtB,CAAC,CAAC,KAAK,KAAK,MAAM;YAChB,CAAC,CAAC,mBAAmB;YACrB,CAAC,CAAC,cAAc,CAAA;IACpB,MAAM,QAAQ,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAA;IAC1F,OAAO,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,IAAI,QAAQ,CAAA;AACxC,CAAC"}