@tpsdev-ai/flair 0.27.1 → 0.29.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 +1 -1
- package/dist/bridges/builtins/index.js +1 -1
- package/dist/bridges/discover.js +1 -1
- package/dist/bridges/runtime/load-plugin.js +1 -1
- package/dist/bridges/scaffold.js +3 -3
- package/dist/bridges/types.js +1 -1
- package/dist/cli.js +148 -26
- package/dist/rem/runner.js +2 -2
- package/dist/resources/MemoryReflect.js +1 -1
- package/dist/resources/RecordUsage.js +15 -1
- package/dist/resources/embeddings-provider.js +8 -38
- package/dist/resources/mcp-tools.js +9 -1
- package/dist/resources/memory-reflect-lib.js +1 -1
- package/dist/resources/migrations/embedding-stamp.js +23 -0
- package/dist/resources/migrations/graph-heal.js +250 -0
- package/dist/resources/migrations/registry.js +11 -5
- package/dist/resources/models-dir.js +55 -0
- package/dist/resources/record-types.js +2 -2
- package/dist/resources/rerank-provider.js +244 -36
- package/dist/resources/usage-recording.js +72 -6
- package/dist/resources/version.js +33 -0
- package/docs/assets/flair-cross-orchestrator.cast +1 -1
- package/docs/bridges.md +3 -3
- package/docs/mcp-clients.md +3 -1
- package/docs/n8n.md +1 -2
- package/docs/notes/rem-ux.md +1 -1
- package/docs/rem.md +2 -0
- package/docs/rerank-provisioning.md +40 -6
- package/package.json +4 -1
- package/schemas/memory.graphql +37 -12
|
@@ -13,8 +13,8 @@ turning it on (`FLAIR_RERANK_ENABLED=true`) or running the recall-bench A/B.
|
|
|
13
13
|
|
|
14
14
|
| `FLAIR_RERANK_MODEL` | GGUF filename (under `models/`) | Source | Inference mode |
|
|
15
15
|
|---|---|---|---|
|
|
16
|
-
| `
|
|
17
|
-
| `
|
|
16
|
+
| `jina-reranker-v2` (**default**, working) | `jina-reranker-v2-base.Q8_0.gguf` | `gpustack/jina-reranker-v2-base-multilingual-GGUF` (q8_0) | rank-pooling cross-encoder |
|
|
17
|
+
| `qwen3-reranker-0.6b-q8` (**experimental** — see Known limitation) | `Qwen3-Reranker-0.6B-q8_0.gguf` | `Mungert/Qwen3-Reranker-0.6B-GGUF` (q8_0) | generative yes/no |
|
|
18
18
|
|
|
19
19
|
Download into `models/` next to the embedding GGUF, e.g.:
|
|
20
20
|
|
|
@@ -36,11 +36,17 @@ vector order — it never blocks or breaks search.
|
|
|
36
36
|
| Env var | Default | Meaning |
|
|
37
37
|
|---|---|---|
|
|
38
38
|
| `FLAIR_RERANK_ENABLED` | unset (**OFF**) | Master flag. `"true"` to enable. |
|
|
39
|
-
| `FLAIR_RERANK_MODEL` | `
|
|
39
|
+
| `FLAIR_RERANK_MODEL` | `jina-reranker-v2` | Model + inference mode (table above). Re-read on every rerank call — changing it takes effect on the NEXT call (that call pays a one-time model-(re)load cost and can itself fall back to vector order if the load exceeds `FLAIR_RERANK_BUDGET_MS`; subsequent calls run at normal latency). |
|
|
40
40
|
| `FLAIR_RERANK_TOPN` | `50` | Candidate count fed to the reranker; caps the HNSW fetch. |
|
|
41
41
|
| `FLAIR_RERANK_BUDGET_MS` | `2500` | Hard latency budget; exceeded → vector order. |
|
|
42
42
|
| `FLAIR_RERANK_MIN_CANDIDATES` | `2` | Skip rerank below this many candidates. |
|
|
43
43
|
|
|
44
|
+
Candidate document (and query) text is truncated to a per-model context budget
|
|
45
|
+
before it ever reaches the engine — see `resources/rerank-provider.ts`'s file
|
|
46
|
+
header ("Context-budget truncation"). This is not operator-configurable
|
|
47
|
+
(the budgets are derived from each mode's fixed context size); flagged here
|
|
48
|
+
only so a truncated rerank input isn't a surprise.
|
|
49
|
+
|
|
44
50
|
## Why this serving path (not Ollama, not a microservice)
|
|
45
51
|
|
|
46
52
|
- **In-process node-llama-cpp** is the same engine the embedding engine already
|
|
@@ -62,6 +68,34 @@ detects this (`out.length === 0`), throws, and **fails open to vector order** (i
|
|
|
62
68
|
never writes corrupt scores). Net effect today: with `FLAIR_RERANK_MODEL=qwen3-...`
|
|
63
69
|
the rerank stage cleanly no-ops inside Harper.
|
|
64
70
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
71
|
+
flair#811 (the live-corpus Phase-1 gate) found the qwen3 path erroring on every
|
|
72
|
+
call in production and root-caused two compounding issues, fixed in that PR:
|
|
73
|
+
|
|
74
|
+
1. **Context overflow on real documents.** The offline pilot's 16-doc fixture was
|
|
75
|
+
short synthetic prose; real memory content routinely exceeds either model's
|
|
76
|
+
small context window (1024 tokens for the generative context, 2048 for the
|
|
77
|
+
rank context). `resources/rerank-provider.ts` now truncates every (query, doc)
|
|
78
|
+
pair to a budget derived from each mode's actual context size before it ever
|
|
79
|
+
reaches the engine (see that file's header). This doesn't fix the dual-backend
|
|
80
|
+
empty-logits limitation above, but it removes overflow as a SEPARATE, more
|
|
81
|
+
easily hit failure mode — and may have been a contributing cause of the
|
|
82
|
+
empty-logits symptom itself (an overflowing `controlledEvaluate` call doesn't
|
|
83
|
+
throw the way `rankAll` does; it's plausible an oversized prompt silently
|
|
84
|
+
context-shifted rather than decoding cleanly, though we couldn't confirm
|
|
85
|
+
this without a live repro).
|
|
86
|
+
2. **Config not re-read after first init.** The provider used to cache which
|
|
87
|
+
model was loaded PERMANENTLY on first successful (or failed) init — a later
|
|
88
|
+
change to `FLAIR_RERANK_MODEL` had no effect until the process restarted, so
|
|
89
|
+
"configured model X, served model Y" could persist silently for the life of
|
|
90
|
+
the process. Now re-validated on every call (`needsReinit()`); a config
|
|
91
|
+
change is picked up on the next rerank.
|
|
92
|
+
|
|
93
|
+
**Given the above, `jina-reranker-v2` is now the DEFAULT model** — its rank-API
|
|
94
|
+
path (`createRankingContext()` / `rankAll`) completes inside Harper. `qwen3` stays
|
|
95
|
+
selectable and documented for whoever revisits the dual-backend isolation
|
|
96
|
+
question; it is not the default until the empty-logits limitation is actually
|
|
97
|
+
fixed (truncation alone doesn't fix it — see point 1 above, it only removes a
|
|
98
|
+
compounding cause).
|
|
99
|
+
|
|
100
|
+
See the integration PR / flair#811 for the live recall-bench A/B numbers and the
|
|
101
|
+
go/no-go read on `jina-reranker-v2` as the default.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tpsdev-ai/flair",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.0",
|
|
4
4
|
"packageManager": "bun@1.3.10",
|
|
5
5
|
"description": "Identity, memory, and soul for AI agents. Cryptographic identity (Ed25519), semantic memory with local embeddings, and persistent personality — all in a single process.",
|
|
6
6
|
"type": "module",
|
|
@@ -76,6 +76,9 @@
|
|
|
76
76
|
"@node-llama-cpp/win-arm64": "3.18.1",
|
|
77
77
|
"@node-llama-cpp/win-x64": "3.18.1"
|
|
78
78
|
},
|
|
79
|
+
"overrides": {
|
|
80
|
+
"react-native-fs": "npm:empty-npm-package@1.0.0"
|
|
81
|
+
},
|
|
79
82
|
"devDependencies": {
|
|
80
83
|
"@playwright/test": "1.59.1",
|
|
81
84
|
"@types/node": "24.11.0",
|
package/schemas/memory.graphql
CHANGED
|
@@ -4,7 +4,25 @@ type Memory @table(database: "flair") {
|
|
|
4
4
|
content: String!
|
|
5
5
|
contentHash: String @indexed
|
|
6
6
|
visibility: String
|
|
7
|
-
embedding: [Float] @indexed(type: "HNSW")
|
|
7
|
+
embedding: [Float] @indexed(type: "HNSW", M: 16) # M:16 is Harper's own HNSW default
|
|
8
|
+
# (HierarchicalNavigableSmallWorld M default) — declaring it explicitly is a
|
|
9
|
+
# ZERO behavior / graph-quality change. Its ONLY effect is the recall-heal
|
|
10
|
+
# trigger (resources/migrations/graph-heal.ts): Harper persists each HNSW
|
|
11
|
+
# attribute's option descriptor and, on boot, structurally diffs it against
|
|
12
|
+
# the schema (databases.ts canonicalizeIndexOptions — sorts keys, coerces
|
|
13
|
+
# numeric strings, but does NOT inject defaults, so `{type:"HNSW"}` and
|
|
14
|
+
# `{type:"HNSW",M:16}` are DIFFERENT canonical keys). A store whose descriptor
|
|
15
|
+
# was persisted WITHOUT options (every pre-this-change install) therefore sees
|
|
16
|
+
# a structural diff on the first boot after upgrade → runIndexing clears the
|
|
17
|
+
# graph store and rebuilds it CLEANLY from the already-correct stored vectors
|
|
18
|
+
# (lastIndexedKey reset to undefined). This heals graphs left stale by Harper's
|
|
19
|
+
# incremental HNSW update after a bulk in-place re-embed (the July embedding-
|
|
20
|
+
# stamp re-embed corrupted prod's reverse edges; a fresh index of the SAME
|
|
21
|
+
# vectors finds the true neighbors, the incrementally-updated one didn't).
|
|
22
|
+
# NO re-embed — the stored vectors are untouched; only the graph is rebuilt.
|
|
23
|
+
# Fires once per instance (the descriptor is then persisted to match); brief
|
|
24
|
+
# vector-search 503 window during the rebuild (~seconds; BM25/direct keep
|
|
25
|
+
# serving). Do NOT remove the `M: 16` — reverting it removes the upgrade heal.
|
|
8
26
|
embeddingModel: String @indexed # ops-1l18: previously written (resources/Memory.ts stamps every
|
|
9
27
|
# write) but never DECLARED in this schema, so it was storable but not
|
|
10
28
|
# queryable — Harper's Table.search({conditions}) rejects a condition on
|
|
@@ -26,13 +44,17 @@ type Memory @table(database: "flair") {
|
|
|
26
44
|
usageCount: Int # flair#683: verified-USE signal, distinct from retrievalCount (a
|
|
27
45
|
# search HIT). Additive/nullable — absent reads as 0, existing rows
|
|
28
46
|
# unaffected. NEVER auto-incremented on search/retrieval; the ONLY
|
|
29
|
-
# writer is
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
47
|
+
# writer is resources/usage-recording.ts's recordUsageContribution()
|
|
48
|
+
# — the shared ledger core behind BOTH usage surfaces: POST
|
|
49
|
+
# /RecordUsage (resources/RecordUsage.ts) and citation-on-write
|
|
50
|
+
# (resources/Memory.ts post()/put() → recordCitations(), which also
|
|
51
|
+
# validates each cited id against the writer's read scope,
|
|
52
|
+
# flair#775). It does a targeted get-then-put increment on this
|
|
53
|
+
# field alone (never through Memory.put() — see RecordUsage.ts's
|
|
54
|
+
# module doc for why: usage feedback writes to ANOTHER agent's
|
|
55
|
+
# memory, and Memory's ownership check would 403 every legit
|
|
56
|
+
# call). Drives usageBoost in resources/scoring.ts, which replaces
|
|
57
|
+
# retrievalBoost in compositeScore (retrievalCount was the
|
|
36
58
|
# contaminated "retrieval counted as usage" signal root-caused in
|
|
37
59
|
# flair#623).
|
|
38
60
|
promotionStatus: String # null | "pending" | "approved" | "rejected"
|
|
@@ -137,9 +159,12 @@ type MemoryGrant @table(database: "flair") @export {
|
|
|
137
159
|
# contributed to this memory's usageCount" is a single point-lookup, not a
|
|
138
160
|
# query. This is what makes the anti-gaming dedup rule ("each (agent, memory)
|
|
139
161
|
# pair contributes at most 1 to usageCount" — Sherlock) enforceable: the
|
|
140
|
-
#
|
|
141
|
-
#
|
|
142
|
-
#
|
|
162
|
+
# shared ledger core (resources/usage-recording.ts's recordUsageContribution(),
|
|
163
|
+
# reached via POST /RecordUsage and via citation-on-write's recordCitations())
|
|
164
|
+
# only bumps Memory.usageCount when a NEW row is created here; a repeat call
|
|
165
|
+
# from the same agent for the same memory is a no-op against a row that
|
|
166
|
+
# already exists. resources/MemoryUsage.ts guards this table's own HTTP
|
|
167
|
+
# surface (it is not the writer).
|
|
143
168
|
#
|
|
144
169
|
# `attribution` is OPAQUE — never parsed, never fed to an LLM, never rendered
|
|
145
170
|
# — a free-text "what used this" hint the caller supplies, sanitized
|
|
@@ -154,7 +179,7 @@ type MemoryUsage @table(database: "flair") {
|
|
|
154
179
|
}
|
|
155
180
|
|
|
156
181
|
# MemoryCandidate — staged distillations from the FLAIR-NIGHTLY-REM cycle.
|
|
157
|
-
# Per
|
|
182
|
+
# Per docs/rem.md. Slice 1 of ops-2qq adds the schema +
|
|
158
183
|
# `flair rem candidates` listing command. Future slices wire the nightly
|
|
159
184
|
# cycle that populates this table and the promote/reject endpoints.
|
|
160
185
|
#
|