@squirrelnotes.app/mcp-embeddings 2.2.0 → 2.2.1-test.353
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 +53 -17
- package/dist/cli.js +1819 -454
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
`@squirrelnotes.app/mcp-embeddings` is the Squirrel Notes stdio MCP server
|
|
4
4
|
with **semantic memory search**. `search_memory` finds a memory by its meaning
|
|
5
|
-
as well as its words, so *"
|
|
6
|
-
|
|
5
|
+
as well as its words, so *"food allergies"* finds *"Is allergic to peanuts"*,
|
|
6
|
+
which shares no word with it.
|
|
7
7
|
|
|
8
8
|
It is the same server as [`@squirrelnotes.app/mcp`](https://www.npmjs.com/package/@squirrelnotes.app/mcp):
|
|
9
9
|
the same tools, the same inputs and the same output shape. It is built from the
|
|
@@ -100,16 +100,31 @@ The vector file can be deleted at any time; it is rebuilt when needed.
|
|
|
100
100
|
|
|
101
101
|
- Without this package, `search_memory` is lexical: BM25 over the words of each
|
|
102
102
|
memory's text, entity and tags, times a recency decay per category.
|
|
103
|
-
- With it, two
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
103
|
+
- With it, the two scores each hit returns are fused (feature 0050, in place
|
|
104
|
+
of reciprocal rank fusion; feature 0054, "words win, age on meaning").
|
|
105
|
+
The fused value is 0.3 × `lexicalScore` + 0.7 × the semantic part × the
|
|
106
|
+
recency decay, where the semantic part is 0 at or below the 0.35 floor, 1
|
|
107
|
+
at a cosine of 0.75 or above, and linear between. The decay is applied
|
|
108
|
+
once, to the semantic part only, so age does not fade a memory's word
|
|
109
|
+
match. A hit that holds every query word (`lexicalScore` 1) scores 0.5 +
|
|
110
|
+
half the fused value, any other hit half of it: so those hits come first,
|
|
111
|
+
and `score` never rises down the list. Of two hits on the same side of 0.5
|
|
112
|
+
with the same recency weight (the same age and category), one at least as
|
|
113
|
+
high on both `lexicalScore` and `semanticScore`, and higher on one, ranks
|
|
114
|
+
first; ties go to the higher cosine. The weight 0.3
|
|
115
|
+
was chosen after measuring on the recall gate's corpus (any weight between
|
|
116
|
+
0 and 1 keeps that order); the span 0.4 was fixed before measuring and
|
|
117
|
+
belongs to this model's cosine range.
|
|
118
|
+
- The members are the memories whose words match and those at or above the
|
|
119
|
+
0.35 floor. Below that, a memory is returned only if its words match.
|
|
120
|
+
- An old memory matched by words keeps its word part whatever its age: only
|
|
121
|
+
the meaning part is discounted. One that holds every query word ranks above
|
|
122
|
+
any memory matched by meaning alone, and one that holds some of them can
|
|
123
|
+
still rank above a fresh memory matched by meaning alone (feature 0054,
|
|
124
|
+
settling proposal 0074's open question 2). Lexical search is unchanged: BM25
|
|
125
|
+
times the decay.
|
|
110
126
|
- `score` is on a 0–1 scale here, and unbounded BM25 in the base package. It
|
|
111
|
-
orders one response only
|
|
112
|
-
whatever its relevance. The keys are the same in both.
|
|
127
|
+
orders one response only. The keys are the same in both.
|
|
113
128
|
- To judge a hit, use the absolute scores: `semanticScore` (the cosine
|
|
114
129
|
similarity, reported for every hit, also those below 0.35 found by words) and
|
|
115
130
|
`lexicalScore` (the share of the query's content words, stopwords aside).
|
|
@@ -121,9 +136,21 @@ The vector file can be deleted at any time; it is rebuilt when needed.
|
|
|
121
136
|
2026-10-13). `semanticScore` is a cosine, −1 to 1
|
|
122
137
|
(in practice about −0.1 to 0.9). `ranking` is `hybrid` when the semantic
|
|
123
138
|
order ran, `lexical` while the model loads or after it fails.
|
|
124
|
-
-
|
|
125
|
-
|
|
126
|
-
|
|
139
|
+
- Accents on Latin letters are ignored by word matching in both packages
|
|
140
|
+
(`creme` finds "crème", `strasse` finds "Straße"). Word matching works in
|
|
141
|
+
any script in both packages: Greek, Cyrillic or Korean by words, and
|
|
142
|
+
Chinese, Japanese, Thai, Lao, Khmer and Myanmar, written without spaces, by
|
|
143
|
+
pairs of characters (a one-character query counts half for each pair
|
|
144
|
+
holding it). Other forms of a word are not matched (`тёмная` does not find
|
|
145
|
+
"тёмную", and a two-syllable Korean query such as `서울` does not find
|
|
146
|
+
"서울에", where a particle is attached), and accents on letters of other
|
|
147
|
+
scripts still count.
|
|
148
|
+
The model reads English: embeddings add little for other languages.
|
|
149
|
+
- A hyphenated word matches whole (`pihole` or `Pi-hole`), and each of its
|
|
150
|
+
parts counts half; a query word of one or two letters matches only that
|
|
151
|
+
whole word, or a hyphenated word's part of the same spelling (half).
|
|
152
|
+
- A query with no letter or digit in any script (most emoji, or punctuation, alone)
|
|
153
|
+
always comes back with a `note`.
|
|
127
154
|
It says the query cannot be searched, unless the semantic ranking actually
|
|
128
155
|
ran, in which case it says the results were found only by meaning.
|
|
129
156
|
|
|
@@ -143,8 +170,12 @@ is lexical too.
|
|
|
143
170
|
|
|
144
171
|
**First searches.** Each memory is embedded once, then only again when it
|
|
145
172
|
changes (its revision moves). A search spends at most 8 seconds embedding
|
|
146
|
-
memories that have no vector yet
|
|
147
|
-
|
|
173
|
+
memories that have no vector yet. Until a later search embeds them, the rest
|
|
174
|
+
have no `semanticScore`: they are returned only if their words match, and
|
|
175
|
+
their fused value is at most 0.3, so during this warm-up a partial word
|
|
176
|
+
match not yet embedded can rank below a memory found by meaning alone (a
|
|
177
|
+
match on every query word still ranks first).
|
|
178
|
+
Measured on an Apple M1 Pro: 500 memories in 4.4 s, 5,000
|
|
148
179
|
in 26.7 s.
|
|
149
180
|
|
|
150
181
|
## Model integrity
|
|
@@ -173,7 +204,12 @@ recall@5 of lexical and hybrid search on 500 memories and 160 queries.
|
|
|
173
204
|
zero-knowledge encryption makes unreadable.
|
|
174
205
|
- Hybrid search must gain at least 15 points on paraphrased queries, and must
|
|
175
206
|
not lose on exact-word queries.
|
|
176
|
-
-
|
|
207
|
+
- Since feature 0050 it also gates, by words alone, a small ranking set of
|
|
208
|
+
stand-ins for reported misses (hyphenated words, short fragments) and a
|
|
209
|
+
ten-query set in other scripts (lexical recall@5 at least 0.8), and reports
|
|
210
|
+
recall@1 and MRR beside recall@5.
|
|
211
|
+
- The latest results are in ADR-0444 and the feature 0050 notes in the
|
|
212
|
+
Squirrel Notes repository.
|
|
177
213
|
|
|
178
214
|
## Environment variables
|
|
179
215
|
|