@ultimat3/cache 28.0.0 → 29.0.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 +7 -0
- package/package.json +3 -3
- package/src/semantic.ts +16 -0
package/README.md
CHANGED
|
@@ -430,6 +430,13 @@ is a driver seam for that reason; a Postgres/pgvector-backed implementation does
|
|
|
430
430
|
yet here (`@ultimat3/ai`'s `postgresVectorStore()` is a separate store, for RAG retrieval, not this
|
|
431
431
|
cache).
|
|
432
432
|
|
|
433
|
+
A similarity that is not a number is not a match. A pair with no defined cosine — one side
|
|
434
|
+
carrying a `NaN` component, or a dot product and norms that overflow together — makes
|
|
435
|
+
`cosineSimilarity` answer `NaN`: honestly, rather than a `0` that would rank a directionless
|
|
436
|
+
vector above every opposed one. The lookup SKIPS such a record: it misses, rather than answering
|
|
437
|
+
one question with another's entry. Every comparison against `NaN` is false, so a record that
|
|
438
|
+
reached the floor unchecked would have passed it, at any floor — `0` included.
|
|
439
|
+
|
|
433
440
|
## Errors
|
|
434
441
|
|
|
435
442
|
| Code | Cause |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ultimat3/cache",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "29.0.0",
|
|
4
4
|
"description": "Tagged caching: request memo, LRU, Redis, CDN — one invalidation graph",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -25,13 +25,13 @@
|
|
|
25
25
|
"LICENSE"
|
|
26
26
|
],
|
|
27
27
|
"engines": {
|
|
28
|
-
"bun": ">=1.4.
|
|
28
|
+
"bun": ">=1.4.4"
|
|
29
29
|
},
|
|
30
30
|
"scripts": {
|
|
31
31
|
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
32
32
|
"test": "bun test"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@ultimat3/core": "
|
|
35
|
+
"@ultimat3/core": "29.0.0"
|
|
36
36
|
}
|
|
37
37
|
}
|
package/src/semantic.ts
CHANGED
|
@@ -54,6 +54,17 @@ export interface SemanticCacheOptions {
|
|
|
54
54
|
readonly clock?: Clock;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Cosine similarity — and the honest answer for a pair that has none: a `NaN` component, or a
|
|
59
|
+
* dot product and norms that overflow together (`1e200` on both sides), leaves the cosine
|
|
60
|
+
* UNDEFINED, and this answers `NaN` rather than a `0` that would rank a vector with no direction
|
|
61
|
+
* above every opposed one (the rule `@ultimat3/ai`'s `cosine` keeps on purpose).
|
|
62
|
+
*
|
|
63
|
+
* `NaN` is not a verdict — the CALLER decides what a nonfinite similarity means. `lookup` skips
|
|
64
|
+
* a record whose similarity is not finite: it is not a candidate, so the entry cannot answer a
|
|
65
|
+
* question it was never asked. A finite similarity is the floor's business, as any other is — a
|
|
66
|
+
* finite dot over an overflowing norm is the `0`, and the floor decides it.
|
|
67
|
+
*/
|
|
57
68
|
export function cosineSimilarity(a: Embedding, b: Embedding): number {
|
|
58
69
|
if (a.length !== b.length || a.length === 0) return 0;
|
|
59
70
|
let dot = 0;
|
|
@@ -114,6 +125,11 @@ export function memorySemanticCache(options: SemanticCacheOptions = {}): Semanti
|
|
|
114
125
|
let best: SemanticHit<T> | undefined;
|
|
115
126
|
for (const record of live()) {
|
|
116
127
|
const similarity = cosineSimilarity(embedding, record.embedding);
|
|
128
|
+
// A similarity that is not a number is not a match. Every comparison against `NaN` is
|
|
129
|
+
// false, so a broken vector SKIPPED the floor below, became `best`, and the cache
|
|
130
|
+
// answered a question it was never asked — a worse failure than a miss, because nothing
|
|
131
|
+
// said so. The floor did not fail to hold; the comparison against it never happened.
|
|
132
|
+
if (!Number.isFinite(similarity)) continue;
|
|
117
133
|
if (similarity < floor) continue;
|
|
118
134
|
if (best === undefined || similarity > best.similarity) {
|
|
119
135
|
best = { value: record.value as T, similarity, key: record.key };
|