@squirrelnotes.app/mcp-embeddings 2.2.0-test.350 → 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 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 *"what coffee do they order?"* can find *"Orders a
6
- flat white with oat milk"*.
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 orders are fused by reciprocal rank fusion (k = 60): the
104
- lexical order, and the semantic order (cosine similarity between the query
105
- and each memory, times the same recency decay). Each order counts the decay
106
- once, and the fused score is not multiplied again. A memory in both orders
107
- ranks above one in only one.
108
- - A semantic match must reach a minimum similarity of 0.35. Below that, a
109
- memory is returned only if its words match.
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: a memory found by one order alone scores about 0.5
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
- - Words outside ASCII letters and digits never match lexically, in either
125
- package. Embeddings can find some of these memories (see *Recall*).
126
- - A query with no ASCII letters or digits always comes back with a `note`.
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; the rest still rank lexically until a later
147
- search embeds them. Measured on an Apple M1 Pro: 500 memories in 4.4 s, 5,000
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
- - The latest results are in ADR-0444 in the Squirrel Notes repository.
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