@gamaze/hicortex 0.15.1 → 0.15.3
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 +10 -2
- package/dist/consolidate.d.ts +0 -3
- package/dist/consolidate.js +7 -6
- package/dist/eval/recall-sweep.d.ts +59 -0
- package/dist/eval/recall-sweep.js +715 -0
- package/dist/index.js +1 -1
- package/dist/init.js +27 -0
- package/dist/mcp-server.js +32 -8
- package/dist/memory-instructions.js +1 -1
- package/dist/nightly.js +3 -1
- package/dist/recall-index.d.ts +4 -1
- package/dist/recall-index.js +2 -2
- package/dist/recall-registry.d.ts +39 -1
- package/dist/recall-registry.js +52 -1
- package/dist/retrieval.d.ts +68 -3
- package/dist/retrieval.js +158 -9
- package/dist/schema-prototypes.d.ts +15 -0
- package/dist/schema-prototypes.js +24 -0
- package/dist/storage.js +10 -0
- package/dist/telemetry.d.ts +17 -0
- package/dist/telemetry.js +31 -0
- package/dist/uninstall.js +10 -0
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -56,9 +56,9 @@ The plugin connects to `http://127.0.0.1:8787` by default. For a remote server,
|
|
|
56
56
|
|
|
57
57
|
## Requirements
|
|
58
58
|
|
|
59
|
-
- Node.js
|
|
59
|
+
- Node.js 20+
|
|
60
60
|
- **Server mode:** LLM required — Ollama 9b+ (recommended), Claude CLI, or API key (Anthropic, OpenAI, etc.). ~500MB disk for database + embedding model.
|
|
61
|
-
- **Client mode:** No local LLM needed. Node.js
|
|
61
|
+
- **Client mode:** No local LLM needed. Node.js 20+ and network access to the server are sufficient.
|
|
62
62
|
- **OC plugin:** Requires a running Hicortex server. No local LLM, database, or embedder in the plugin itself.
|
|
63
63
|
|
|
64
64
|
## What Happens Automatically
|
|
@@ -210,6 +210,13 @@ Config at `~/.hicortex/config.json`. Created by `init`. Key options:
|
|
|
210
210
|
| `contextAgents` | Per-agent context modes (0.13): `{ "<id>": "override" \| "global" \| "off" }`. Absent + no `agents/<id>/` dir → every agent gets the global set. Boot-time (restart to apply) — see [Per-agent context](#per-agent-context-013) |
|
|
211
211
|
| `agentName` | This install's per-agent context id sent as `?agent=`. **Unset by default** (CC shares the global context — no `?agent=` sent). Explicit opt-in via `init --agent-name <name>`; `init --agent-name ""` clears it. An empty/whitespace value equals unset |
|
|
212
212
|
| `nightlyHour` | Local hour (0–23) for the nightly job installed by `init` (defaults: client 2, server 3). Applied on fresh installs; existing schedules are never overwritten |
|
|
213
|
+
| `scoreSimilarityWeight` | Weight of semantic similarity in the ranking score (default: 0.50) |
|
|
214
|
+
| `scoreStrengthWeight` | Weight of effective strength — importance/use/recency of access (default: 0.20) |
|
|
215
|
+
| `scoreConnectionsWeight` | Weight of graph centrality (default: 0.15) |
|
|
216
|
+
| `scoreRecencyWeight` | Weight of the slow recency curve (default: 0.15) |
|
|
217
|
+
| `freshnessBoostDays` | Fresh-memory window: new memories rank higher for this many days (default: 7) |
|
|
218
|
+
| `freshnessBoostWeight` | Size of the fresh-memory bonus at age 0, fading linearly to 0 at the window edge (default: 0.15; set 0 to disable) |
|
|
219
|
+
| `supersededDemotion` | Score multiplier for a memory a later decision reversed (default: 0.50) |
|
|
213
220
|
| `decayHalfLifeDays` | Memory decay half-life in days at reference importance (default: 365). Larger = slower forgetting; importance, access, and links slow it further |
|
|
214
221
|
| `searchLimit` / `recentLimit` | Default result counts for search (8) and recent (12) |
|
|
215
222
|
| `recentWindowDays` | Candidate window for recent recall (default: 180) |
|
|
@@ -218,6 +225,7 @@ Config at `~/.hicortex/config.json`. Created by `init`. Key options:
|
|
|
218
225
|
| `recallMinSimilarity` | Relevance floor for index entries (default: 0.55; text-search matches always pass) |
|
|
219
226
|
| `recallReshowTurns` | Turns before an already-shown memory may reappear in the same session (default: 30) |
|
|
220
227
|
| `recallMinPromptChars` | Prompts shorter than this skip the recall index (default: 20) |
|
|
228
|
+
| `sessionIntentWeight` | Blend weight of the session-intent rolling centroid in the recall search vector: `query = (1-w)·prompt + w·centroid` (default: 0.33; set 0 to disable — pure-prompt recall, the kill-switch). The first turn of a session searches with pure prompt and seeds the centroid; subsequent turns blend so recall follows the session's intent instead of being query-literal. The EMA rate (0.4) is a shipped constant, not configurable |
|
|
221
229
|
| `dedupMergeThreshold` | Minimum cosine similarity for `hicortex dedup` to cluster memories as near-duplicates (default: 0.92) |
|
|
222
230
|
| `supersessionMinSimilarity` | Minimum cosine similarity for a nightly supersession candidate pair (default: 0.80) |
|
|
223
231
|
| `supersessionMaxCalls` | Max classify-tier LLM calls the nightly's supersession stage spends per run (default: 30) |
|
package/dist/consolidate.d.ts
CHANGED
|
@@ -135,12 +135,9 @@ export declare function classifyRelationship(source: Memory, target: Memory, sim
|
|
|
135
135
|
export declare const DEFAULT_SUPERSESSION_MIN_SIMILARITY = 0.8;
|
|
136
136
|
/** Default max classify-tier LLM calls (pairs evaluated) spent per nightly run. */
|
|
137
137
|
export declare const DEFAULT_SUPERSESSION_MAX_CALLS = 30;
|
|
138
|
-
/** Default multiplier applied to a superseded memory's base_strength. */
|
|
139
|
-
export declare const DEFAULT_SUPERSESSION_PENALTY = 0.5;
|
|
140
138
|
export interface SupersessionOptions {
|
|
141
139
|
minSimilarity?: number;
|
|
142
140
|
maxCalls?: number;
|
|
143
|
-
penalty?: number;
|
|
144
141
|
}
|
|
145
142
|
export interface SupersessionStageResult {
|
|
146
143
|
scanned: number;
|
package/dist/consolidate.js
CHANGED
|
@@ -38,7 +38,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
38
38
|
};
|
|
39
39
|
})();
|
|
40
40
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
-
exports.
|
|
41
|
+
exports.DEFAULT_SUPERSESSION_MAX_CALLS = exports.DEFAULT_SUPERSESSION_MIN_SIMILARITY = exports.BudgetTracker = exports.REFLECTION_CONTRADICTION_MIN_COSINE = exports.l2ToCosine = exports.CROSS_PROJECT_LINK_THRESHOLD = exports.CONSOLIDATE_LINK_TOP_K = exports.CONSOLIDATE_LINK_THRESHOLD = void 0;
|
|
42
42
|
exports.isContradictionCandidate = isContradictionCandidate;
|
|
43
43
|
exports.parseJsonLenient = parseJsonLenient;
|
|
44
44
|
exports.rebuildContentModuleIndex = rebuildContentModuleIndex;
|
|
@@ -850,9 +850,7 @@ exports.DEFAULT_SUPERSESSION_MIN_SIMILARITY = 0.8;
|
|
|
850
850
|
/** Default max classify-tier LLM calls (pairs evaluated) spent per nightly run. */
|
|
851
851
|
exports.DEFAULT_SUPERSESSION_MAX_CALLS = 30;
|
|
852
852
|
/** Default multiplier applied to a superseded memory's base_strength. */
|
|
853
|
-
exports.DEFAULT_SUPERSESSION_PENALTY = 0.5;
|
|
854
853
|
/** Floor under which a superseded memory's base_strength never drops. */
|
|
855
|
-
const SUPERSESSION_STRENGTH_FLOOR = 0.1;
|
|
856
854
|
/** Neighbor pool size before shape/older/similarity filtering narrows to top 5. */
|
|
857
855
|
const SUPERSESSION_NEIGHBOR_POOL = 15;
|
|
858
856
|
/** Older-neighbor pairs kept per candidate after filtering. */
|
|
@@ -965,7 +963,6 @@ async function stageSupersession(db, llm, budget, embedFn, dryRun, stateDir, opt
|
|
|
965
963
|
};
|
|
966
964
|
const minSimilarity = validNumber(options.minSimilarity, exports.DEFAULT_SUPERSESSION_MIN_SIMILARITY, (n) => n > 0 && n <= 1);
|
|
967
965
|
const maxCalls = validNumber(options.maxCalls, exports.DEFAULT_SUPERSESSION_MAX_CALLS, (n) => n >= 0);
|
|
968
|
-
const penalty = validNumber(options.penalty, exports.DEFAULT_SUPERSESSION_PENALTY, (n) => n > 0 && n <= 1);
|
|
969
966
|
const startCursor = (0, state_js_1.loadState)(stateDir).supersessionCursor ?? 0;
|
|
970
967
|
const rows = db
|
|
971
968
|
.prepare(`SELECT rowid AS __rowid, * FROM memories
|
|
@@ -1011,9 +1008,13 @@ async function stageSupersession(db, llm, budget, embedFn, dryRun, stateDir, opt
|
|
|
1011
1008
|
}
|
|
1012
1009
|
if (verdict) {
|
|
1013
1010
|
const cosine = (0, retrieval_js_1.l2ToCosine)(neighbor.distance);
|
|
1011
|
+
// The link IS the signal (0.15.2): retrieval demotes superseded
|
|
1012
|
+
// memories via an explicit scoring multiplier (supersededDemotion,
|
|
1013
|
+
// retrieval.ts). The old base_strength penalty was retired because it
|
|
1014
|
+
// (a) fought the config-tunable strength weight and (b) leaked into
|
|
1015
|
+
// prune eligibility — a reversed decision must rank lower, not edge
|
|
1016
|
+
// toward deletion.
|
|
1014
1017
|
storage.addLink(db, neighbor.id, candidate.id, "superseded_by", cosine);
|
|
1015
|
-
const newStrength = Math.max(SUPERSESSION_STRENGTH_FLOOR, (neighbor.base_strength ?? 0.5) * penalty);
|
|
1016
|
-
storage.updateMemory(db, neighbor.id, { base_strength: newStrength });
|
|
1017
1018
|
superseded++;
|
|
1018
1019
|
console.log(`[hicortex] Supersession: ${neighbor.id.slice(0, 8)} superseded_by ${candidate.id.slice(0, 8)} (cosine ${cosine.toFixed(3)})`);
|
|
1019
1020
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Recall@k sweep eval for session-intent keying (#192, commit 0867d6c).
|
|
4
|
+
*
|
|
5
|
+
* SHIP GATE: does blending the prompt with the per-session EMA centroid
|
|
6
|
+
* (retrieval.blendQueryVector) improve recall across rephrased turns, AND
|
|
7
|
+
* what does it COST when a session shifts topics mid-stream? Picks the
|
|
8
|
+
* default `sessionIntentWeight`.
|
|
9
|
+
*
|
|
10
|
+
* Two scenario families, same corpus:
|
|
11
|
+
*
|
|
12
|
+
* FOCUSED — 6 sessions (one per topic), 4 turns each of GENUINE REPHRASES
|
|
13
|
+
* of one intent. Tests the UPSIDE: does the centroid pull drifting
|
|
14
|
+
* rephrases back on-topic? (recall@5 / p@5 should rise with w.)
|
|
15
|
+
*
|
|
16
|
+
* SHIFT — 5 sessions, each 2 turns on topic A then 2 turns on topic B (a
|
|
17
|
+
* clean mid-session topic change). Tests the DOWNSIDE that focused-only
|
|
18
|
+
* can't see: a higher weight leaves the centroid partly A right after the
|
|
19
|
+
* shift, so the first turn(s) on B may LAG (lower recall@5 for B). The
|
|
20
|
+
* load-bearing read-out is post-shift recovery at turn-3 (first B turn)
|
|
21
|
+
* and turn-4, plus turns-to-recover.
|
|
22
|
+
*
|
|
23
|
+
* Method (both families):
|
|
24
|
+
* - Synthetic corpus of 30 memories across 6 well-separated topics (5 each),
|
|
25
|
+
* embedded with the REAL bge-small-en-v1.5 model (the production embedder).
|
|
26
|
+
* - For each weight w in {0.0, 0.2, 0.4, 0.5, 0.6, 0.8}: fresh
|
|
27
|
+
* SessionRecallRegistry per session; per turn, embed the prompt ONCE,
|
|
28
|
+
* blend with the live centroid, pass the blended vector to retrieve() via
|
|
29
|
+
* queryEmbedding, record recall@5 + p@5 for the turn's CURRENT topic,
|
|
30
|
+
* then fold the prompt into the centroid (EMA α=0.4).
|
|
31
|
+
*
|
|
32
|
+
* Fairness controls (load-bearing — the eval is useless if these slip):
|
|
33
|
+
* - `noStrengthen: true` on every retrieve(): the DB stays STATIC across all
|
|
34
|
+
* retrieve calls. Strengthening would mutate effective_strength/access_count
|
|
35
|
+
* between runs and contaminate cross-weight comparisons.
|
|
36
|
+
* - Uniform memory metadata: every memory has base_strength=0.5, created_at
|
|
37
|
+
* ≈ now, access_count=0, and NO links. So effective_strength, recency,
|
|
38
|
+
* connections, and the freshness boost are all uniform → the ONLY
|
|
39
|
+
* discriminator is vector cosine + RRF rank. That isolates the blend.
|
|
40
|
+
* - Cold-exposure slots are a no-op here (all candidates equally cold),
|
|
41
|
+
* so the top-k is the plain score order.
|
|
42
|
+
* - The centroid update is weight-INDEPENDENT (EMA of prompts at α=0.4), so
|
|
43
|
+
* the per-turn centroid is identical across all weights for a given
|
|
44
|
+
* session; only the blend differs. Embeddings are precomputed once.
|
|
45
|
+
*
|
|
46
|
+
* Metrics (per turn, for the turn's CURRENT topic):
|
|
47
|
+
* - recall@5 — did >=1 same-topic memory surface in the top-5? (coarse; the
|
|
48
|
+
* requested ship-gate metric — saturates on a small corpus.)
|
|
49
|
+
* - p@5 — on-topic count in the top-5 (0..5, finer).
|
|
50
|
+
* - recall@1 — was the SINGLE top result on-topic? (finest; focused only.)
|
|
51
|
+
*
|
|
52
|
+
* Honest by construction: it prints whatever the numbers are, including
|
|
53
|
+
* w=0 winning, the blend hurting a focused scenario, or high weights lagging
|
|
54
|
+
* badly post-shift. Report written to data/eval-recall-sweep/report.md and
|
|
55
|
+
* printed to stdout.
|
|
56
|
+
*
|
|
57
|
+
* Run: npm run eval:recall-sweep (== node dist/eval/recall-sweep.js)
|
|
58
|
+
*/
|
|
59
|
+
export {};
|