@gamaze/hicortex 0.20.7 → 0.20.9
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 -41
- package/dist/calibration.d.ts +174 -0
- package/dist/calibration.js +231 -0
- package/dist/capture.d.ts +15 -3
- package/dist/capture.js +10 -1
- package/dist/classify-domains.d.ts +6 -0
- package/dist/classify-domains.js +7 -1
- package/dist/cli.js +2 -3
- package/dist/config-read.d.ts +1 -1
- package/dist/config-read.js +96 -9
- package/dist/consolidate.d.ts +79 -68
- package/dist/consolidate.js +218 -174
- package/dist/dashboard.d.ts +4 -3
- package/dist/dedup.d.ts +34 -26
- package/dist/dedup.js +91 -57
- package/dist/distiller.js +1 -1
- package/dist/domain-classify.d.ts +7 -6
- package/dist/domain-classify.js +12 -10
- package/dist/eval/decay-eval.d.ts +3 -3
- package/dist/eval/decay-eval.js +4 -4
- package/dist/eval/planted-eval.d.ts +26 -0
- package/dist/eval/planted-eval.js +97 -0
- package/dist/eval/planted-fixtures.d.ts +107 -0
- package/dist/eval/planted-fixtures.js +283 -0
- package/dist/eval/planted-harness.d.ts +176 -0
- package/dist/eval/planted-harness.js +649 -0
- package/dist/index.js +4 -3
- package/dist/init.d.ts +9 -3
- package/dist/init.js +52 -9
- package/dist/llm.d.ts +43 -58
- package/dist/llm.js +87 -101
- package/dist/mcp-server.js +29 -29
- package/dist/nightly.js +105 -103
- package/dist/nofit.d.ts +4 -11
- package/dist/nofit.js +6 -23
- package/dist/recall-index.d.ts +30 -28
- package/dist/recall-index.js +21 -18
- package/dist/recall-registry.d.ts +2 -1
- package/dist/recall-registry.js +35 -1
- package/dist/reconsolidation.d.ts +124 -72
- package/dist/reconsolidation.js +359 -148
- package/dist/relink.js +3 -4
- package/dist/retrieval.d.ts +68 -35
- package/dist/retrieval.js +292 -104
- package/dist/run-deadline.d.ts +62 -0
- package/dist/run-deadline.js +73 -0
- package/dist/schema-prototypes.d.ts +3 -3
- package/dist/schema-prototypes.js +3 -3
- package/dist/state.d.ts +2 -3
- package/dist/storage.d.ts +16 -16
- package/dist/storage.js +62 -24
- package/dist/telemetry.d.ts +8 -7
- package/dist/token-budget.js +3 -4
- package/dist/type-classify.js +4 -4
- package/dist/types.d.ts +95 -155
- package/domains.example.json +4 -5
- package/hermes-plugin/hicortex/README.md +2 -2
- package/openclaw.plugin.json +1 -1
- package/package.json +2 -1
- package/pi-extension/hicortex/README.md +1 -1
- package/server.json +3 -3
|
@@ -121,9 +121,9 @@ export declare function computeTagWeights(db: Database.Database, memoryId: strin
|
|
|
121
121
|
*
|
|
122
122
|
* Used by the no-fit path (nofit.ts, owner amendment 07.07): when the LLM
|
|
123
123
|
* says no domain fits, the memory can still earn a WEAK primary from pure
|
|
124
|
-
* embedding association — provided the best cosine clears the
|
|
125
|
-
*
|
|
126
|
-
* the argmax).
|
|
124
|
+
* embedding association — provided the best cosine clears the weak-primary
|
|
125
|
+
* floor (release-managed since #408; the caller checks the floor, this
|
|
126
|
+
* function just reports the argmax).
|
|
127
127
|
*
|
|
128
128
|
* Returns null when the memory has no stored vector or no configured domain
|
|
129
129
|
* has a prototype (nothing to associate against). Ties resolve to the FIRST
|
|
@@ -239,9 +239,9 @@ function computeTagWeights(db, memoryId, tags, prototypes) {
|
|
|
239
239
|
*
|
|
240
240
|
* Used by the no-fit path (nofit.ts, owner amendment 07.07): when the LLM
|
|
241
241
|
* says no domain fits, the memory can still earn a WEAK primary from pure
|
|
242
|
-
* embedding association — provided the best cosine clears the
|
|
243
|
-
*
|
|
244
|
-
* the argmax).
|
|
242
|
+
* embedding association — provided the best cosine clears the weak-primary
|
|
243
|
+
* floor (release-managed since #408; the caller checks the floor, this
|
|
244
|
+
* function just reports the argmax).
|
|
245
245
|
*
|
|
246
246
|
* Returns null when the memory has no stored vector or no configured domain
|
|
247
247
|
* has a prototype (nothing to associate against). Ties resolve to the FIRST
|
package/dist/state.d.ts
CHANGED
|
@@ -55,9 +55,8 @@ export interface HicortexState {
|
|
|
55
55
|
* B) — highest memories.rowid whose decision/correction candidates have
|
|
56
56
|
* been evaluated (or infra-skipped) this run. Absent/0 = never run. Unlike
|
|
57
57
|
* relinkCursor/domainCursor (separate resumable CLI commands), this cursor
|
|
58
|
-
* advances
|
|
59
|
-
*
|
|
60
|
-
* gradually over many nights.
|
|
58
|
+
* advances within the shared nightly LLM call budget as part of the regular
|
|
59
|
+
* nightly — the corpus is back-processed gradually over many nights.
|
|
61
60
|
*/
|
|
62
61
|
supersessionCursor?: number;
|
|
63
62
|
/**
|
package/dist/storage.d.ts
CHANGED
|
@@ -132,15 +132,15 @@ export declare function vectorSearch(db: Database.Database, queryEmbedding: Floa
|
|
|
132
132
|
distance: number;
|
|
133
133
|
}>;
|
|
134
134
|
/**
|
|
135
|
-
* BM25F field weights (
|
|
136
|
-
*
|
|
137
|
-
* declaration in db.ts (content, project, domain) —
|
|
138
|
-
* takes weights POSITIONALLY, so a new FTS column
|
|
139
|
-
* same position or the weighting silently shifts.
|
|
140
|
-
* (project/domain) over body so cross-scope noise
|
|
141
|
-
* frequency (the marine "battery" memory on a hardware
|
|
142
|
-
* without excluding it — the same "graded, never binary"
|
|
143
|
-
* computeScore's affinity terms.
|
|
135
|
+
* BM25F field weights (release-managed since #408 — the defaults resolve from
|
|
136
|
+
* calibration.ts; {@link configureBm25Fts} is the eval/test seam). The order
|
|
137
|
+
* mirrors the FTS5 column declaration in db.ts (content, project, domain) —
|
|
138
|
+
* `bm25(memories_fts, …)` takes weights POSITIONALLY, so a new FTS column
|
|
139
|
+
* MUST be added here in the same position or the weighting silently shifts.
|
|
140
|
+
* Defaults favor scope fields (project/domain) over body so cross-scope noise
|
|
141
|
+
* that wins on raw token frequency (the marine "battery" memory on a hardware
|
|
142
|
+
* query) is demoted without excluding it — the same "graded, never binary"
|
|
143
|
+
* discipline as computeScore's affinity terms.
|
|
144
144
|
*/
|
|
145
145
|
export interface Bm25Weights {
|
|
146
146
|
body: number;
|
|
@@ -148,14 +148,14 @@ export interface Bm25Weights {
|
|
|
148
148
|
domain: number;
|
|
149
149
|
}
|
|
150
150
|
/**
|
|
151
|
-
* Configure BM25F weights from
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
* key. Range [0, ∞) — a 0 weight effectively drops that
|
|
155
|
-
* negative values are rejected (BM25F sign semantics
|
|
156
|
-
* the resolved set for logging/tests.
|
|
151
|
+
* Configure BM25F weights from RESOLVED overrides (the eval/test seam — #408;
|
|
152
|
+
* production calls it with no argument so storage and retrieval rank with the
|
|
153
|
+
* identical calibration defaults). Invalid/out-of-range values keep the
|
|
154
|
+
* shipped default per key. Range [0, ∞) — a 0 weight effectively drops that
|
|
155
|
+
* field from the score; negative values are rejected (BM25F sign semantics
|
|
156
|
+
* break otherwise). Returns the resolved set for logging/tests.
|
|
157
157
|
*/
|
|
158
|
-
export declare function configureBm25Fts(
|
|
158
|
+
export declare function configureBm25Fts(overrides?: Partial<Bm25Weights> | null): Bm25Weights;
|
|
159
159
|
/** Current resolved weights (tests + status output). */
|
|
160
160
|
export declare function getBm25Weights(): Bm25Weights;
|
|
161
161
|
/**
|
package/dist/storage.js
CHANGED
|
@@ -3,6 +3,39 @@
|
|
|
3
3
|
* Storage layer — CRUD operations for the SQLite + sqlite-vec database.
|
|
4
4
|
* Ported from hicortex/storage.py. All functions are synchronous (better-sqlite3).
|
|
5
5
|
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
6
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
40
|
exports.FTS_MATCH_MAX_TOKENS = void 0;
|
|
8
41
|
exports.embedToBlob = embedToBlob;
|
|
@@ -38,6 +71,7 @@ exports.getAllLinkCounts = getAllLinkCounts;
|
|
|
38
71
|
exports.getUnscoredMemories = getUnscoredMemories;
|
|
39
72
|
const node_crypto_1 = require("node:crypto");
|
|
40
73
|
const schema_prototypes_js_1 = require("./schema-prototypes.js");
|
|
74
|
+
const CALIBRATION = __importStar(require("./calibration.js"));
|
|
41
75
|
// ---------------------------------------------------------------------------
|
|
42
76
|
// Helpers
|
|
43
77
|
// ---------------------------------------------------------------------------
|
|
@@ -354,28 +388,28 @@ function vectorSearch(db, queryEmbedding, limit = 10, excludeIds = []) {
|
|
|
354
388
|
return results;
|
|
355
389
|
}
|
|
356
390
|
const BM25_DEFAULTS = {
|
|
357
|
-
body:
|
|
358
|
-
project:
|
|
359
|
-
domain:
|
|
391
|
+
body: CALIBRATION.BM25_WEIGHT_BODY,
|
|
392
|
+
project: CALIBRATION.BM25_WEIGHT_PROJECT,
|
|
393
|
+
domain: CALIBRATION.BM25_WEIGHT_DOMAIN,
|
|
360
394
|
};
|
|
361
395
|
let bm25Weights = { ...BM25_DEFAULTS };
|
|
362
396
|
/**
|
|
363
|
-
* Configure BM25F weights from
|
|
364
|
-
*
|
|
365
|
-
*
|
|
366
|
-
* key. Range [0, ∞) — a 0 weight effectively drops that
|
|
367
|
-
* negative values are rejected (BM25F sign semantics
|
|
368
|
-
* the resolved set for logging/tests.
|
|
369
|
-
*/
|
|
370
|
-
function configureBm25Fts(
|
|
371
|
-
const num = (
|
|
372
|
-
const
|
|
373
|
-
return Number.isFinite(
|
|
397
|
+
* Configure BM25F weights from RESOLVED overrides (the eval/test seam — #408;
|
|
398
|
+
* production calls it with no argument so storage and retrieval rank with the
|
|
399
|
+
* identical calibration defaults). Invalid/out-of-range values keep the
|
|
400
|
+
* shipped default per key. Range [0, ∞) — a 0 weight effectively drops that
|
|
401
|
+
* field from the score; negative values are rejected (BM25F sign semantics
|
|
402
|
+
* break otherwise). Returns the resolved set for logging/tests.
|
|
403
|
+
*/
|
|
404
|
+
function configureBm25Fts(overrides) {
|
|
405
|
+
const num = (v, dflt) => {
|
|
406
|
+
const n = Number(v);
|
|
407
|
+
return Number.isFinite(n) && n >= 0 ? n : dflt;
|
|
374
408
|
};
|
|
375
409
|
bm25Weights = {
|
|
376
|
-
body: num(
|
|
377
|
-
project: num(
|
|
378
|
-
domain: num(
|
|
410
|
+
body: num(overrides?.body, BM25_DEFAULTS.body),
|
|
411
|
+
project: num(overrides?.project, BM25_DEFAULTS.project),
|
|
412
|
+
domain: num(overrides?.domain, BM25_DEFAULTS.domain),
|
|
379
413
|
};
|
|
380
414
|
return { ...bm25Weights };
|
|
381
415
|
}
|
|
@@ -487,14 +521,18 @@ function searchFts(db, query, limit = 10, sourceAgent) {
|
|
|
487
521
|
* Create a link between two memories.
|
|
488
522
|
*/
|
|
489
523
|
function addLink(db, sourceId, targetId, relationship, strength = 0.5) {
|
|
490
|
-
// Guard: superseded_by and
|
|
491
|
-
// correction-resolution signals, so never let a
|
|
492
|
-
// clobber an existing one for the same pair — INSERT
|
|
493
|
-
// otherwise silently remove the resolution (corrected_by is
|
|
494
|
-
// exactly like superseded_by, #384 AC9
|
|
495
|
-
|
|
524
|
+
// Guard: superseded_by, corrected_by, and conflicts are the ranking-demotion /
|
|
525
|
+
// correction-resolution / conflict-preservation signals, so never let a
|
|
526
|
+
// different relationship clobber an existing one for the same pair — INSERT
|
|
527
|
+
// OR REPLACE would otherwise silently remove the resolution (corrected_by is
|
|
528
|
+
// protected exactly like superseded_by, #384 AC9; conflicts joins the set in
|
|
529
|
+
// #393 guard-C — a conflicts edge marks the pair as never-blendable, so it
|
|
530
|
+
// must survive arbitrary later link writes exactly the same way).
|
|
531
|
+
if (relationship !== "superseded_by" &&
|
|
532
|
+
relationship !== "corrected_by" &&
|
|
533
|
+
relationship !== "conflicts") {
|
|
496
534
|
const protectedLink = db
|
|
497
|
-
.prepare("SELECT 1 FROM memory_links WHERE source_id = ? AND target_id = ? AND relationship IN ('superseded_by', 'corrected_by') LIMIT 1")
|
|
535
|
+
.prepare("SELECT 1 FROM memory_links WHERE source_id = ? AND target_id = ? AND relationship IN ('superseded_by', 'corrected_by', 'conflicts') LIMIT 1")
|
|
498
536
|
.get(sourceId, targetId);
|
|
499
537
|
if (protectedLink)
|
|
500
538
|
return;
|
package/dist/telemetry.d.ts
CHANGED
|
@@ -91,17 +91,17 @@ export interface TelemetryPayload {
|
|
|
91
91
|
* `runConsolidation`'s status: "completed" | "skipped" | "failed", plus
|
|
92
92
|
* "no_llm" when consolidation was skipped because no LLM was configured,
|
|
93
93
|
* "throttled" (#246) when the run was skipped because the
|
|
94
|
-
* `llmTokensPerMonth` fair-use cap was projected to be exceeded,
|
|
95
|
-
* "endpoint_down" (#337) when the
|
|
96
|
-
*
|
|
97
|
-
* (retried next run), never reported
|
|
98
|
-
* fail soft.
|
|
94
|
+
* `llmTokensPerMonth` fair-use cap was projected to be exceeded,
|
|
95
|
+
* "endpoint_down" (#337) when the LLM circuit breaker was open after the
|
|
96
|
+
* run, and "deferred" (#405) when the run-wide wall-clock deadline fired —
|
|
97
|
+
* the latter two are TRANSIENT states (retried next run), never reported
|
|
98
|
+
* as "completed" even though the stages fail soft.
|
|
99
99
|
* "skipped" = the built-in nothing-to-do short-circuit (no new + no unscored
|
|
100
100
|
* memories → zero LLM calls), NOT a failure. Lets the fleet aggregate tell a
|
|
101
101
|
* real consolidation run from a no-op without repurposing `ok` (which is the
|
|
102
102
|
* capture-health signal). 0.17+.
|
|
103
103
|
*/
|
|
104
|
-
consolidation?: "completed" | "skipped" | "failed" | "no_llm" | "throttled" | "endpoint_down";
|
|
104
|
+
consolidation?: "completed" | "skipped" | "failed" | "no_llm" | "throttled" | "endpoint_down" | "deferred";
|
|
105
105
|
/**
|
|
106
106
|
* Total LLM tokens consumed by THIS nightly's consolidation (#246) — the
|
|
107
107
|
* BudgetTracker total. Server-mode only (capture-only + client runs make no
|
|
@@ -111,7 +111,8 @@ export interface TelemetryPayload {
|
|
|
111
111
|
*/
|
|
112
112
|
tokens_this_run?: number;
|
|
113
113
|
/**
|
|
114
|
-
* True when the per-tenant consolidation budget (`
|
|
114
|
+
* True when the per-tenant consolidation budget (`nightlyLlmCallBudget`,
|
|
115
|
+
* #405 — formerly consolidateMaxLlmCalls)
|
|
115
116
|
* was exhausted this run (#255) — LLM-bound stages deferred remaining work.
|
|
116
117
|
* A quality-degradation signal concentrated on heavy users; absent on a
|
|
117
118
|
* pre-#255 ping, a capture-only/no-LLM/throttled/skipped run, or when the
|
package/dist/token-budget.js
CHANGED
|
@@ -105,10 +105,9 @@ function recordDistillUsage(stateDir, usage) {
|
|
|
105
105
|
let periodStart = "";
|
|
106
106
|
(0, state_js_1.updateState)((s) => {
|
|
107
107
|
const prev = s.llmTokensThisPeriod;
|
|
108
|
-
// Monthly reset
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
new Date(prev.periodStart).getUTCMonth() !== new Date().getUTCMonth();
|
|
108
|
+
// Monthly reset — the ONE staleness helper (#405; was a hand-rolled copy
|
|
109
|
+
// of shouldThrottleTokens's check).
|
|
110
|
+
const stale = (0, consolidate_js_1.isStaleTokenPeriod)(prev?.periodStart);
|
|
112
111
|
if (stale) {
|
|
113
112
|
s.llmTokensThisPeriod = {
|
|
114
113
|
prompt: usage.prompt,
|
package/dist/type-classify.js
CHANGED
|
@@ -151,10 +151,10 @@ async function classifyMemoryType(content, llm) {
|
|
|
151
151
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
152
152
|
let raw;
|
|
153
153
|
try {
|
|
154
|
-
// No per-call cap (#391): the
|
|
155
|
-
//
|
|
156
|
-
//
|
|
157
|
-
const r = await llm.
|
|
154
|
+
// No per-call cap (#391/#405): maxTokens — the ONE ceiling — resolves
|
|
155
|
+
// inside complete(); the old hardcoded 20 starved reasoning models
|
|
156
|
+
// whose thinking ate the whole output budget.
|
|
157
|
+
const r = await llm.complete(prompt);
|
|
158
158
|
raw = r.text;
|
|
159
159
|
}
|
|
160
160
|
catch (err) {
|