@sentry/junior-memory 0.130.0 → 0.132.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/dist/db/schema.d.ts +21 -0
- package/dist/index.js +13 -38
- package/dist/index.js.map +1 -1
- package/dist/ranking.d.ts +1 -5
- package/migrations/0006_friendly_hydra.sql +4 -0
- package/migrations/meta/0006_snapshot.json +386 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +2 -2
- package/src/db/schema.ts +11 -1
- package/src/ranking.ts +1 -11
- package/src/store.ts +3 -46
package/dist/ranking.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { MemoryRecord } from "./store";
|
|
2
2
|
export interface MemoryMatch {
|
|
3
|
-
exactIdentifier: boolean;
|
|
4
3
|
lexical?: {
|
|
5
4
|
rank: number;
|
|
6
5
|
};
|
|
@@ -10,10 +9,7 @@ export interface MemoryMatch {
|
|
|
10
9
|
rank: number;
|
|
11
10
|
};
|
|
12
11
|
}
|
|
13
|
-
/**
|
|
14
|
-
* Keep exact structured-identifier matches in the strongest relevance tier,
|
|
15
|
-
* then fuse lexical and vector ranks without comparing provider raw scores.
|
|
16
|
-
*/
|
|
12
|
+
/** Fuse lexical and vector ranks without comparing provider raw scores. */
|
|
17
13
|
export declare function rankMemoryMatches(matches: MemoryMatch[], options: {
|
|
18
14
|
channelPrefix?: string;
|
|
19
15
|
nowMs: number;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
CREATE EXTENSION IF NOT EXISTS btree_gin;--> statement-breakpoint
|
|
2
|
+
DROP INDEX "junior_memory_memories_search_idx";--> statement-breakpoint
|
|
3
|
+
ALTER TABLE "junior_memory_memories" ADD COLUMN "search_vector" "tsvector" GENERATED ALWAYS AS (to_tsvector('english', "content")) STORED;--> statement-breakpoint
|
|
4
|
+
CREATE INDEX "junior_memory_memories_search_idx" ON "junior_memory_memories" USING gin ("scope","scope_key","search_vector") WHERE "junior_memory_memories"."archived_at_ms" IS NULL AND "junior_memory_memories"."superseded_at_ms" IS NULL AND "junior_memory_memories"."superseded_by_id" IS NULL;
|
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "f18fa309-6485-40f3-921a-5d65552fbdf6",
|
|
3
|
+
"prevId": "6948ea3f-2e44-49ce-aa94-8a993ce61cec",
|
|
4
|
+
"version": "7",
|
|
5
|
+
"dialect": "postgresql",
|
|
6
|
+
"tables": {
|
|
7
|
+
"public.junior_memory_embeddings": {
|
|
8
|
+
"name": "junior_memory_embeddings",
|
|
9
|
+
"schema": "",
|
|
10
|
+
"columns": {
|
|
11
|
+
"memory_id": {
|
|
12
|
+
"name": "memory_id",
|
|
13
|
+
"type": "text",
|
|
14
|
+
"primaryKey": true,
|
|
15
|
+
"notNull": true
|
|
16
|
+
},
|
|
17
|
+
"provider": {
|
|
18
|
+
"name": "provider",
|
|
19
|
+
"type": "text",
|
|
20
|
+
"primaryKey": false,
|
|
21
|
+
"notNull": true
|
|
22
|
+
},
|
|
23
|
+
"model": {
|
|
24
|
+
"name": "model",
|
|
25
|
+
"type": "text",
|
|
26
|
+
"primaryKey": false,
|
|
27
|
+
"notNull": true
|
|
28
|
+
},
|
|
29
|
+
"dimensions": {
|
|
30
|
+
"name": "dimensions",
|
|
31
|
+
"type": "integer",
|
|
32
|
+
"primaryKey": false,
|
|
33
|
+
"notNull": true
|
|
34
|
+
},
|
|
35
|
+
"metric": {
|
|
36
|
+
"name": "metric",
|
|
37
|
+
"type": "text",
|
|
38
|
+
"primaryKey": false,
|
|
39
|
+
"notNull": true
|
|
40
|
+
},
|
|
41
|
+
"content_hash": {
|
|
42
|
+
"name": "content_hash",
|
|
43
|
+
"type": "text",
|
|
44
|
+
"primaryKey": false,
|
|
45
|
+
"notNull": true
|
|
46
|
+
},
|
|
47
|
+
"embedding": {
|
|
48
|
+
"name": "embedding",
|
|
49
|
+
"type": "vector(1536)",
|
|
50
|
+
"primaryKey": false,
|
|
51
|
+
"notNull": true
|
|
52
|
+
},
|
|
53
|
+
"created_at_ms": {
|
|
54
|
+
"name": "created_at_ms",
|
|
55
|
+
"type": "bigint",
|
|
56
|
+
"primaryKey": false,
|
|
57
|
+
"notNull": true
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"indexes": {
|
|
61
|
+
"junior_memory_embeddings_model_idx": {
|
|
62
|
+
"name": "junior_memory_embeddings_model_idx",
|
|
63
|
+
"columns": [
|
|
64
|
+
{
|
|
65
|
+
"expression": "provider",
|
|
66
|
+
"isExpression": false,
|
|
67
|
+
"asc": true,
|
|
68
|
+
"nulls": "last"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"expression": "model",
|
|
72
|
+
"isExpression": false,
|
|
73
|
+
"asc": true,
|
|
74
|
+
"nulls": "last"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"expression": "dimensions",
|
|
78
|
+
"isExpression": false,
|
|
79
|
+
"asc": true,
|
|
80
|
+
"nulls": "last"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"expression": "metric",
|
|
84
|
+
"isExpression": false,
|
|
85
|
+
"asc": true,
|
|
86
|
+
"nulls": "last"
|
|
87
|
+
}
|
|
88
|
+
],
|
|
89
|
+
"isUnique": false,
|
|
90
|
+
"concurrently": false,
|
|
91
|
+
"method": "btree",
|
|
92
|
+
"with": {}
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
"foreignKeys": {
|
|
96
|
+
"junior_memory_embeddings_memory_id_junior_memory_memories_id_fk": {
|
|
97
|
+
"name": "junior_memory_embeddings_memory_id_junior_memory_memories_id_fk",
|
|
98
|
+
"tableFrom": "junior_memory_embeddings",
|
|
99
|
+
"tableTo": "junior_memory_memories",
|
|
100
|
+
"columnsFrom": ["memory_id"],
|
|
101
|
+
"columnsTo": ["id"],
|
|
102
|
+
"onDelete": "cascade",
|
|
103
|
+
"onUpdate": "no action"
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
"compositePrimaryKeys": {},
|
|
107
|
+
"uniqueConstraints": {},
|
|
108
|
+
"policies": {},
|
|
109
|
+
"checkConstraints": {
|
|
110
|
+
"junior_memory_embeddings_metric_check": {
|
|
111
|
+
"name": "junior_memory_embeddings_metric_check",
|
|
112
|
+
"value": "\"junior_memory_embeddings\".\"metric\" IN ('cosine')"
|
|
113
|
+
},
|
|
114
|
+
"junior_memory_embeddings_dimensions_check": {
|
|
115
|
+
"name": "junior_memory_embeddings_dimensions_check",
|
|
116
|
+
"value": "\"junior_memory_embeddings\".\"dimensions\" = 1536"
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
"isRLSEnabled": false
|
|
120
|
+
},
|
|
121
|
+
"public.junior_memory_memories": {
|
|
122
|
+
"name": "junior_memory_memories",
|
|
123
|
+
"schema": "",
|
|
124
|
+
"columns": {
|
|
125
|
+
"id": {
|
|
126
|
+
"name": "id",
|
|
127
|
+
"type": "text",
|
|
128
|
+
"primaryKey": true,
|
|
129
|
+
"notNull": true
|
|
130
|
+
},
|
|
131
|
+
"scope": {
|
|
132
|
+
"name": "scope",
|
|
133
|
+
"type": "text",
|
|
134
|
+
"primaryKey": false,
|
|
135
|
+
"notNull": true
|
|
136
|
+
},
|
|
137
|
+
"scope_key": {
|
|
138
|
+
"name": "scope_key",
|
|
139
|
+
"type": "text",
|
|
140
|
+
"primaryKey": false,
|
|
141
|
+
"notNull": true
|
|
142
|
+
},
|
|
143
|
+
"type": {
|
|
144
|
+
"name": "type",
|
|
145
|
+
"type": "text",
|
|
146
|
+
"primaryKey": false,
|
|
147
|
+
"notNull": true
|
|
148
|
+
},
|
|
149
|
+
"subject_type": {
|
|
150
|
+
"name": "subject_type",
|
|
151
|
+
"type": "text",
|
|
152
|
+
"primaryKey": false,
|
|
153
|
+
"notNull": true
|
|
154
|
+
},
|
|
155
|
+
"subject_key": {
|
|
156
|
+
"name": "subject_key",
|
|
157
|
+
"type": "text",
|
|
158
|
+
"primaryKey": false,
|
|
159
|
+
"notNull": false
|
|
160
|
+
},
|
|
161
|
+
"content": {
|
|
162
|
+
"name": "content",
|
|
163
|
+
"type": "text",
|
|
164
|
+
"primaryKey": false,
|
|
165
|
+
"notNull": true
|
|
166
|
+
},
|
|
167
|
+
"search_vector": {
|
|
168
|
+
"name": "search_vector",
|
|
169
|
+
"type": "tsvector",
|
|
170
|
+
"primaryKey": false,
|
|
171
|
+
"notNull": false,
|
|
172
|
+
"generated": {
|
|
173
|
+
"as": "to_tsvector('english', \"content\")",
|
|
174
|
+
"type": "stored"
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
"source_platform": {
|
|
178
|
+
"name": "source_platform",
|
|
179
|
+
"type": "text",
|
|
180
|
+
"primaryKey": false,
|
|
181
|
+
"notNull": true
|
|
182
|
+
},
|
|
183
|
+
"source_key": {
|
|
184
|
+
"name": "source_key",
|
|
185
|
+
"type": "text",
|
|
186
|
+
"primaryKey": false,
|
|
187
|
+
"notNull": true
|
|
188
|
+
},
|
|
189
|
+
"idempotency_key": {
|
|
190
|
+
"name": "idempotency_key",
|
|
191
|
+
"type": "text",
|
|
192
|
+
"primaryKey": false,
|
|
193
|
+
"notNull": false
|
|
194
|
+
},
|
|
195
|
+
"observed_at_ms": {
|
|
196
|
+
"name": "observed_at_ms",
|
|
197
|
+
"type": "bigint",
|
|
198
|
+
"primaryKey": false,
|
|
199
|
+
"notNull": true
|
|
200
|
+
},
|
|
201
|
+
"created_at_ms": {
|
|
202
|
+
"name": "created_at_ms",
|
|
203
|
+
"type": "bigint",
|
|
204
|
+
"primaryKey": false,
|
|
205
|
+
"notNull": true
|
|
206
|
+
},
|
|
207
|
+
"expires_at_ms": {
|
|
208
|
+
"name": "expires_at_ms",
|
|
209
|
+
"type": "bigint",
|
|
210
|
+
"primaryKey": false,
|
|
211
|
+
"notNull": false
|
|
212
|
+
},
|
|
213
|
+
"superseded_at_ms": {
|
|
214
|
+
"name": "superseded_at_ms",
|
|
215
|
+
"type": "bigint",
|
|
216
|
+
"primaryKey": false,
|
|
217
|
+
"notNull": false
|
|
218
|
+
},
|
|
219
|
+
"superseded_by_id": {
|
|
220
|
+
"name": "superseded_by_id",
|
|
221
|
+
"type": "text",
|
|
222
|
+
"primaryKey": false,
|
|
223
|
+
"notNull": false
|
|
224
|
+
},
|
|
225
|
+
"archived_at_ms": {
|
|
226
|
+
"name": "archived_at_ms",
|
|
227
|
+
"type": "bigint",
|
|
228
|
+
"primaryKey": false,
|
|
229
|
+
"notNull": false
|
|
230
|
+
},
|
|
231
|
+
"archive_reason": {
|
|
232
|
+
"name": "archive_reason",
|
|
233
|
+
"type": "text",
|
|
234
|
+
"primaryKey": false,
|
|
235
|
+
"notNull": false
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
"indexes": {
|
|
239
|
+
"junior_memory_memories_visible_idx": {
|
|
240
|
+
"name": "junior_memory_memories_visible_idx",
|
|
241
|
+
"columns": [
|
|
242
|
+
{
|
|
243
|
+
"expression": "scope",
|
|
244
|
+
"isExpression": false,
|
|
245
|
+
"asc": true,
|
|
246
|
+
"nulls": "last"
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
"expression": "scope_key",
|
|
250
|
+
"isExpression": false,
|
|
251
|
+
"asc": true,
|
|
252
|
+
"nulls": "last"
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
"expression": "created_at_ms",
|
|
256
|
+
"isExpression": false,
|
|
257
|
+
"asc": false,
|
|
258
|
+
"nulls": "last"
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
"expression": "id",
|
|
262
|
+
"isExpression": false,
|
|
263
|
+
"asc": true,
|
|
264
|
+
"nulls": "last"
|
|
265
|
+
}
|
|
266
|
+
],
|
|
267
|
+
"isUnique": false,
|
|
268
|
+
"where": "\"junior_memory_memories\".\"archived_at_ms\" IS NULL AND \"junior_memory_memories\".\"superseded_at_ms\" IS NULL AND \"junior_memory_memories\".\"superseded_by_id\" IS NULL",
|
|
269
|
+
"concurrently": false,
|
|
270
|
+
"method": "btree",
|
|
271
|
+
"with": {}
|
|
272
|
+
},
|
|
273
|
+
"junior_memory_memories_expiration_idx": {
|
|
274
|
+
"name": "junior_memory_memories_expiration_idx",
|
|
275
|
+
"columns": [
|
|
276
|
+
{
|
|
277
|
+
"expression": "expires_at_ms",
|
|
278
|
+
"isExpression": false,
|
|
279
|
+
"asc": true,
|
|
280
|
+
"nulls": "last"
|
|
281
|
+
}
|
|
282
|
+
],
|
|
283
|
+
"isUnique": false,
|
|
284
|
+
"where": "\"junior_memory_memories\".\"archived_at_ms\" IS NULL AND \"junior_memory_memories\".\"expires_at_ms\" IS NOT NULL",
|
|
285
|
+
"concurrently": false,
|
|
286
|
+
"method": "btree",
|
|
287
|
+
"with": {}
|
|
288
|
+
},
|
|
289
|
+
"junior_memory_memories_search_idx": {
|
|
290
|
+
"name": "junior_memory_memories_search_idx",
|
|
291
|
+
"columns": [
|
|
292
|
+
{
|
|
293
|
+
"expression": "scope",
|
|
294
|
+
"isExpression": false,
|
|
295
|
+
"asc": true,
|
|
296
|
+
"nulls": "last"
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
"expression": "scope_key",
|
|
300
|
+
"isExpression": false,
|
|
301
|
+
"asc": true,
|
|
302
|
+
"nulls": "last"
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
"expression": "search_vector",
|
|
306
|
+
"isExpression": false,
|
|
307
|
+
"asc": true,
|
|
308
|
+
"nulls": "last"
|
|
309
|
+
}
|
|
310
|
+
],
|
|
311
|
+
"isUnique": false,
|
|
312
|
+
"where": "\"junior_memory_memories\".\"archived_at_ms\" IS NULL AND \"junior_memory_memories\".\"superseded_at_ms\" IS NULL AND \"junior_memory_memories\".\"superseded_by_id\" IS NULL",
|
|
313
|
+
"concurrently": false,
|
|
314
|
+
"method": "gin",
|
|
315
|
+
"with": {}
|
|
316
|
+
},
|
|
317
|
+
"junior_memory_memories_idempotency_idx": {
|
|
318
|
+
"name": "junior_memory_memories_idempotency_idx",
|
|
319
|
+
"columns": [
|
|
320
|
+
{
|
|
321
|
+
"expression": "scope",
|
|
322
|
+
"isExpression": false,
|
|
323
|
+
"asc": true,
|
|
324
|
+
"nulls": "last"
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
"expression": "scope_key",
|
|
328
|
+
"isExpression": false,
|
|
329
|
+
"asc": true,
|
|
330
|
+
"nulls": "last"
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
"expression": "idempotency_key",
|
|
334
|
+
"isExpression": false,
|
|
335
|
+
"asc": true,
|
|
336
|
+
"nulls": "last"
|
|
337
|
+
}
|
|
338
|
+
],
|
|
339
|
+
"isUnique": true,
|
|
340
|
+
"where": "\"junior_memory_memories\".\"idempotency_key\" IS NOT NULL AND \"junior_memory_memories\".\"archived_at_ms\" IS NULL AND \"junior_memory_memories\".\"superseded_at_ms\" IS NULL AND \"junior_memory_memories\".\"superseded_by_id\" IS NULL",
|
|
341
|
+
"concurrently": false,
|
|
342
|
+
"method": "btree",
|
|
343
|
+
"with": {}
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
"foreignKeys": {},
|
|
347
|
+
"compositePrimaryKeys": {},
|
|
348
|
+
"uniqueConstraints": {},
|
|
349
|
+
"policies": {},
|
|
350
|
+
"checkConstraints": {
|
|
351
|
+
"junior_memory_memories_scope_check": {
|
|
352
|
+
"name": "junior_memory_memories_scope_check",
|
|
353
|
+
"value": "\"junior_memory_memories\".\"scope\" IN ('personal', 'conversation')"
|
|
354
|
+
},
|
|
355
|
+
"junior_memory_memories_kind_check": {
|
|
356
|
+
"name": "junior_memory_memories_kind_check",
|
|
357
|
+
"value": "\"junior_memory_memories\".\"type\" IN (\n 'preference',\n 'procedure',\n 'knowledge'\n )"
|
|
358
|
+
},
|
|
359
|
+
"junior_memory_memories_subject_type_check": {
|
|
360
|
+
"name": "junior_memory_memories_subject_type_check",
|
|
361
|
+
"value": "\"junior_memory_memories\".\"subject_type\" IN ('user', 'conversation', 'general')"
|
|
362
|
+
},
|
|
363
|
+
"junior_memory_memories_subject_key_check": {
|
|
364
|
+
"name": "junior_memory_memories_subject_key_check",
|
|
365
|
+
"value": "(\"junior_memory_memories\".\"subject_type\" = 'general' AND \"junior_memory_memories\".\"subject_key\" IS NULL) OR (\"junior_memory_memories\".\"subject_type\" IN ('user', 'conversation') AND \"junior_memory_memories\".\"subject_key\" IS NOT NULL AND length(\"junior_memory_memories\".\"subject_key\") > 0)"
|
|
366
|
+
},
|
|
367
|
+
"junior_memory_memories_source_platform_check": {
|
|
368
|
+
"name": "junior_memory_memories_source_platform_check",
|
|
369
|
+
"value": "\"junior_memory_memories\".\"source_platform\" IN ('slack', 'local')"
|
|
370
|
+
}
|
|
371
|
+
},
|
|
372
|
+
"isRLSEnabled": false
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
"enums": {},
|
|
376
|
+
"schemas": {},
|
|
377
|
+
"sequences": {},
|
|
378
|
+
"roles": {},
|
|
379
|
+
"policies": {},
|
|
380
|
+
"views": {},
|
|
381
|
+
"_meta": {
|
|
382
|
+
"columns": {},
|
|
383
|
+
"schemas": {},
|
|
384
|
+
"tables": {}
|
|
385
|
+
}
|
|
386
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentry/junior-memory",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.132.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"commander": "^14.0.3",
|
|
28
28
|
"drizzle-orm": "^0.45.2",
|
|
29
29
|
"zod": "^4.4.3",
|
|
30
|
-
"@sentry/junior-plugin-api": "0.
|
|
30
|
+
"@sentry/junior-plugin-api": "0.132.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/node": "^25.9.1",
|
package/src/db/schema.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { sql } from "drizzle-orm";
|
|
|
8
8
|
import {
|
|
9
9
|
bigint,
|
|
10
10
|
check,
|
|
11
|
+
customType,
|
|
11
12
|
index,
|
|
12
13
|
integer,
|
|
13
14
|
pgTable,
|
|
@@ -24,6 +25,12 @@ import {
|
|
|
24
25
|
MEMORY_KINDS,
|
|
25
26
|
} from "../types";
|
|
26
27
|
|
|
28
|
+
const tsvector = customType<{ data: string }>({
|
|
29
|
+
dataType() {
|
|
30
|
+
return "tsvector";
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
|
|
27
34
|
export const juniorMemoryMemories = pgTable(
|
|
28
35
|
"junior_memory_memories",
|
|
29
36
|
{
|
|
@@ -34,6 +41,9 @@ export const juniorMemoryMemories = pgTable(
|
|
|
34
41
|
subjectType: text("subject_type", { enum: MEMORY_SUBJECT_TYPES }).notNull(),
|
|
35
42
|
subjectKey: text("subject_key"),
|
|
36
43
|
content: text("content").notNull(),
|
|
44
|
+
searchVector: tsvector("search_vector").generatedAlwaysAs(
|
|
45
|
+
sql`to_tsvector('english', "content")`,
|
|
46
|
+
),
|
|
37
47
|
sourcePlatform: text("source_platform", {
|
|
38
48
|
enum: MEMORY_SOURCE_PLATFORMS,
|
|
39
49
|
}).notNull(),
|
|
@@ -59,7 +69,7 @@ export const juniorMemoryMemories = pgTable(
|
|
|
59
69
|
sql`${table.archivedAtMs} IS NULL AND ${table.expiresAtMs} IS NOT NULL`,
|
|
60
70
|
),
|
|
61
71
|
index("junior_memory_memories_search_idx")
|
|
62
|
-
.using("gin",
|
|
72
|
+
.using("gin", table.scope, table.scopeKey, table.searchVector)
|
|
63
73
|
.where(
|
|
64
74
|
sql`${table.archivedAtMs} IS NULL AND ${table.supersededAtMs} IS NULL AND ${table.supersededById} IS NULL`,
|
|
65
75
|
),
|
package/src/ranking.ts
CHANGED
|
@@ -4,7 +4,6 @@ const RECIPROCAL_RANK_FUSION_K = 60;
|
|
|
4
4
|
const ONE_DAY_MS = 24 * 60 * 60 * 1000;
|
|
5
5
|
|
|
6
6
|
export interface MemoryMatch {
|
|
7
|
-
exactIdentifier: boolean;
|
|
8
7
|
lexical?: {
|
|
9
8
|
rank: number;
|
|
10
9
|
};
|
|
@@ -47,10 +46,7 @@ function observedAgeRank(memory: MemoryRecord, nowMs: number): number {
|
|
|
47
46
|
return 0;
|
|
48
47
|
}
|
|
49
48
|
|
|
50
|
-
/**
|
|
51
|
-
* Keep exact structured-identifier matches in the strongest relevance tier,
|
|
52
|
-
* then fuse lexical and vector ranks without comparing provider raw scores.
|
|
53
|
-
*/
|
|
49
|
+
/** Fuse lexical and vector ranks without comparing provider raw scores. */
|
|
54
50
|
export function rankMemoryMatches(
|
|
55
51
|
matches: MemoryMatch[],
|
|
56
52
|
options: {
|
|
@@ -67,17 +63,11 @@ export function rankMemoryMatches(
|
|
|
67
63
|
}
|
|
68
64
|
byId.set(match.memory.id, {
|
|
69
65
|
...existing,
|
|
70
|
-
exactIdentifier: existing.exactIdentifier || match.exactIdentifier,
|
|
71
66
|
...(match.lexical ? { lexical: match.lexical } : {}),
|
|
72
67
|
...(match.vector ? { vector: match.vector } : {}),
|
|
73
68
|
});
|
|
74
69
|
}
|
|
75
70
|
return [...byId.values()].sort((left, right) => {
|
|
76
|
-
const identifierDelta =
|
|
77
|
-
Number(right.exactIdentifier) - Number(left.exactIdentifier);
|
|
78
|
-
if (identifierDelta !== 0) {
|
|
79
|
-
return identifierDelta;
|
|
80
|
-
}
|
|
81
71
|
const scoreDelta = matchScore(right) - matchScore(left);
|
|
82
72
|
if (scoreDelta !== 0) {
|
|
83
73
|
return scoreDelta;
|
package/src/store.ts
CHANGED
|
@@ -128,6 +128,7 @@ const memoryRowSchema = z
|
|
|
128
128
|
id: z.string().min(1),
|
|
129
129
|
idempotencyKey: optionalStringSchema,
|
|
130
130
|
observedAtMs: z.coerce.number(),
|
|
131
|
+
searchVector: z.string().optional(),
|
|
131
132
|
scope: z.enum(MEMORY_SCOPES),
|
|
132
133
|
scopeKey: z.string().min(1),
|
|
133
134
|
sourceKey: z.string().min(1),
|
|
@@ -591,22 +592,6 @@ export async function archiveExpiredMemoryBatch(args: {
|
|
|
591
592
|
return { archivedCount: archivedIds.length };
|
|
592
593
|
}
|
|
593
594
|
|
|
594
|
-
/**
|
|
595
|
-
* Find path-like, dotted, underscored, and multi-part hyphenated identifiers.
|
|
596
|
-
* Two-part hyphenated prose such as "long-running" remains ordinary text.
|
|
597
|
-
*/
|
|
598
|
-
function structuredQueryIdentifiers(query: string): string[] {
|
|
599
|
-
const matches =
|
|
600
|
-
query
|
|
601
|
-
.toLowerCase()
|
|
602
|
-
.match(
|
|
603
|
-
/(?:[a-z0-9][a-z0-9._-]*\/)+[a-z0-9][a-z0-9._-]*|[a-z0-9]+(?:[._][a-z0-9]+)+|[a-z0-9]+(?:-[a-z0-9]+){2,}/g,
|
|
604
|
-
) ?? [];
|
|
605
|
-
return [
|
|
606
|
-
...new Set(matches.map((identifier) => identifier.replace(/\.+$/, ""))),
|
|
607
|
-
];
|
|
608
|
-
}
|
|
609
|
-
|
|
610
595
|
function denseRanks<T>(
|
|
611
596
|
values: T[],
|
|
612
597
|
key: (value: T) => string | number,
|
|
@@ -982,50 +967,23 @@ async function searchVisibleLexicalMemories(args: {
|
|
|
982
967
|
)
|
|
983
968
|
FROM unnest(tsvector_to_array(${queryVector})) AS query_terms(term)
|
|
984
969
|
)`;
|
|
985
|
-
const textsearch =
|
|
970
|
+
const textsearch = juniorMemoryMemories.searchVector;
|
|
986
971
|
const textRank = sql<number>`ts_rank_cd(${textsearch}, ${tsquery})`;
|
|
987
|
-
const identifiers = structuredQueryIdentifiers(args.query);
|
|
988
|
-
const contentTokens = sql`regexp_split_to_array(lower(${juniorMemoryMemories.content}), '[^a-z0-9._/-]+')`;
|
|
989
|
-
const identifierArray =
|
|
990
|
-
identifiers.length > 0
|
|
991
|
-
? sql`ARRAY[${sql.join(
|
|
992
|
-
identifiers.map((identifier) => sql`${identifier}`),
|
|
993
|
-
sql`, `,
|
|
994
|
-
)}]::text[]`
|
|
995
|
-
: undefined;
|
|
996
|
-
const exactIdentifierMatch =
|
|
997
|
-
identifierArray !== undefined
|
|
998
|
-
? sql<boolean>`EXISTS (
|
|
999
|
-
SELECT 1
|
|
1000
|
-
FROM unnest(${contentTokens}) AS content_token(value)
|
|
1001
|
-
CROSS JOIN unnest(${identifierArray}) AS query_identifier(value)
|
|
1002
|
-
WHERE strpos(
|
|
1003
|
-
'/' || regexp_replace(content_token.value, '\\.+$', '') || '/',
|
|
1004
|
-
'/' || query_identifier.value || '/'
|
|
1005
|
-
) > 0
|
|
1006
|
-
)`
|
|
1007
|
-
: sql<boolean>`false`;
|
|
1008
972
|
const rows = await args.db
|
|
1009
973
|
.select({
|
|
1010
|
-
exactIdentifierMatch,
|
|
1011
974
|
memory: juniorMemoryMemories,
|
|
1012
975
|
textRank,
|
|
1013
976
|
})
|
|
1014
977
|
.from(juniorMemoryMemories)
|
|
1015
978
|
.where(and(predicate, sql`${textsearch} @@ ${tsquery}`))
|
|
1016
979
|
.orderBy(
|
|
1017
|
-
...(identifiers.length > 0 ? [desc(exactIdentifierMatch)] : []),
|
|
1018
980
|
desc(textRank),
|
|
1019
981
|
desc(juniorMemoryMemories.observedAtMs),
|
|
1020
982
|
asc(juniorMemoryMemories.id),
|
|
1021
983
|
)
|
|
1022
984
|
.limit(args.limit);
|
|
1023
|
-
const ranks = denseRanks(
|
|
1024
|
-
rows,
|
|
1025
|
-
(row) => `${row.exactIdentifierMatch}:${Number(row.textRank)}`,
|
|
1026
|
-
);
|
|
985
|
+
const ranks = denseRanks(rows, (row) => Number(row.textRank));
|
|
1027
986
|
return rows.map((row, index) => ({
|
|
1028
|
-
exactIdentifier: row.exactIdentifierMatch,
|
|
1029
987
|
lexical: { rank: ranks[index] },
|
|
1030
988
|
memory: parseMemoryRow(row.memory),
|
|
1031
989
|
sourceKey: row.memory.sourceKey,
|
|
@@ -1100,7 +1058,6 @@ async function searchVisibleVectorMemories(args: {
|
|
|
1100
1058
|
}
|
|
1101
1059
|
return [
|
|
1102
1060
|
{
|
|
1103
|
-
exactIdentifier: false,
|
|
1104
1061
|
memory: parseMemoryRow(row.memory),
|
|
1105
1062
|
sourceKey: row.memory.sourceKey,
|
|
1106
1063
|
vector: {
|