@gamaze/hicortex 0.16.0 → 0.16.1
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 -0
- package/dist/consolidate.js +4 -1
- package/dist/distiller.js +19 -12
- package/dist/eval/relevance-eval.d.ts +64 -0
- package/dist/eval/relevance-eval.js +1954 -0
- package/dist/index.js +3 -2
- package/dist/lessons-context.js +3 -2
- package/dist/mcp-server.js +1 -0
- package/dist/prompts.js +22 -6
- package/dist/recall-index.d.ts +43 -4
- package/dist/recall-index.js +40 -8
- package/dist/seed-lesson.d.ts +1 -1
- package/dist/seed-lesson.js +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -226,6 +226,7 @@ Config at `~/.hicortex/config.json`. Created by `init`. Key options:
|
|
|
226
226
|
| `recallMinSimilarity` | Relevance floor for index entries (default: 0.55; text-search matches always pass) |
|
|
227
227
|
| `recallReshowTurns` | Turns before an already-shown memory may reappear in the same session (default: 30) |
|
|
228
228
|
| `recallMinPromptChars` | Prompts shorter than this skip the recall index (default: 20) |
|
|
229
|
+
| `recallTitleChars` | Chars of each memory's first line shown in an index entry (default: 150, range 40–400). Raised from 100 on 2026-08-02: with topic-first memory titles, 150 chars carries the subject *and* its claim, where 100 cut the claim mid-sentence. Costs roughly +74 tokens per 6-line block |
|
|
229
230
|
| `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 |
|
|
230
231
|
| `dedupMergeThreshold` | Minimum cosine similarity for `hicortex dedup` to cluster memories as near-duplicates (default: 0.92) |
|
|
231
232
|
| `supersessionMinSimilarity` | Minimum cosine similarity for a nightly supersession candidate pair (default: 0.80) |
|
package/dist/consolidate.js
CHANGED
|
@@ -307,7 +307,10 @@ async function stageReflection(db, memories, llm, budget, embedFn, dryRun) {
|
|
|
307
307
|
const severity = String(lo.severity ?? "important");
|
|
308
308
|
const confidence = String(lo.confidence ?? "medium");
|
|
309
309
|
const sourcePattern = String(lo.source_pattern ?? "");
|
|
310
|
-
|
|
310
|
+
// No `## Lesson:` prefix: memory_type='lesson' carries the type, and the
|
|
311
|
+
// text is the topic-first first line (display reads the first line, not a
|
|
312
|
+
// header parse — see lessons-context.ts / index.ts).
|
|
313
|
+
let content = `${lessonText}\n\n`;
|
|
311
314
|
content += `**Type:** ${lessonType}\n`;
|
|
312
315
|
content += `**Severity:** ${severity}\n`;
|
|
313
316
|
content += `**Confidence:** ${confidence}\n`;
|
package/dist/distiller.js
CHANGED
|
@@ -314,6 +314,14 @@ async function distillChunk(llm, transcript, projectName, date) {
|
|
|
314
314
|
return { entries: [], dropped: [] };
|
|
315
315
|
}
|
|
316
316
|
const parsed = parseDistilledEntries(result);
|
|
317
|
+
// Smoke alarm (PR #218 review): the prompt enforces topic-first, but models
|
|
318
|
+
// sometimes ignore constraints (cf. the prior max-15-bullet failure). Count
|
|
319
|
+
// entries that still look actor-led or bracket-led so a format regression
|
|
320
|
+
// shows in nightly logs, not months later in the next eval. Non-blocking.
|
|
321
|
+
const offTopic = parsed.filter((e) => /^\s*(user|ai|the user|assistant)\b/i.test(e) || /^\s*\[/.test(e)).length;
|
|
322
|
+
if (parsed.length > 0 && offTopic > 0) {
|
|
323
|
+
console.log(`[hicortex] topic-first check: ${offTopic}/${parsed.length} entries look actor/bracket-led (prompt may be ignored)`);
|
|
324
|
+
}
|
|
317
325
|
const entries = [];
|
|
318
326
|
const dropped = [];
|
|
319
327
|
for (const entry of parsed) {
|
|
@@ -409,23 +417,22 @@ function hasMinimalSubstance(entry) {
|
|
|
409
417
|
function parseDistilledEntries(markdown) {
|
|
410
418
|
const entries = [];
|
|
411
419
|
const lines = markdown.split("\n");
|
|
412
|
-
let currentSection = "";
|
|
413
420
|
for (const line of lines) {
|
|
414
421
|
const trimmed = line.trim();
|
|
415
|
-
//
|
|
416
|
-
|
|
417
|
-
|
|
422
|
+
// Skip all markdown headers (session title, classification, section
|
|
423
|
+
// headings). Sections are NOT prefixed onto entries: each bullet already
|
|
424
|
+
// starts with its [SUBJECT] (topic-first, enforced by prompts.ts), and
|
|
425
|
+
// prepending "[Section]" re-introduced the category-first prefix the
|
|
426
|
+
// 2026-08-02 corpus rewrite removed. The section label is unused
|
|
427
|
+
// downstream (distilled memories all store memory_type='episode').
|
|
428
|
+
if (trimmed.startsWith("# ") ||
|
|
429
|
+
trimmed.startsWith("## ") ||
|
|
430
|
+
trimmed.startsWith("### ")) {
|
|
418
431
|
continue;
|
|
419
432
|
}
|
|
420
|
-
//
|
|
421
|
-
if (trimmed.startsWith("# ") || trimmed.startsWith("## "))
|
|
422
|
-
continue;
|
|
423
|
-
// Bullet items are individual memories
|
|
433
|
+
// Bullet items are individual, already topic-first memories.
|
|
424
434
|
if (trimmed.startsWith("- ") && trimmed.length > 5) {
|
|
425
|
-
|
|
426
|
-
? `[${currentSection}] ${trimmed.slice(2)}`
|
|
427
|
-
: trimmed.slice(2);
|
|
428
|
-
entries.push(entry);
|
|
435
|
+
entries.push(trimmed.slice(2));
|
|
429
436
|
}
|
|
430
437
|
}
|
|
431
438
|
return entries;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Real-query relevance + SNIPPET eval — recall QUALITY on real agent prompts.
|
|
4
|
+
*
|
|
5
|
+
* v2 (spec `specs/2026-08-02-relevance-eval.md`) extends the v1 selection-only
|
|
6
|
+
* eval with the SNIPPET layer: v1 asked "did retrieve() surface the right
|
|
7
|
+
* memories?" (judge sees up to 2000 chars). Production shows the agent only a
|
|
8
|
+
* ~100-char one-liner (`recall-index.ts#memoryTitle`), so a memory can be
|
|
9
|
+
* genuinely relevant while its rendered line is useless — v1 scored that as a
|
|
10
|
+
* win. v2 grades BOTH: `full_verdict` (selection quality, judge sees full
|
|
11
|
+
* content) and `line_verdict` (snippet quality, judge sees ONLY the rendered
|
|
12
|
+
* production one-liner — imported from `recall-index.ts`, never reimplemented).
|
|
13
|
+
*
|
|
14
|
+
* v2 additions (spec §4, §5, §6, §6b) layered onto the v1 base (prompt
|
|
15
|
+
* sampling, readonly snapshot handling, embed-once + neverCalledEmbed,
|
|
16
|
+
* lenient JSON parse, distribution/CI reporting):
|
|
17
|
+
* 1. Dual verdict per surfaced memory — TWO separate, blind judge calls.
|
|
18
|
+
* 2. Snippet-length sweep (100/200/300/title+1st-sentence) on a fixed
|
|
19
|
+
* 40-prompt subset (8 per source).
|
|
20
|
+
* 3. Similarity-floor + retrieval-source analysis (near-free — logged, not
|
|
21
|
+
* re-judged).
|
|
22
|
+
* 4. Token-cost estimate (char/4) per K and per snippet-length variant.
|
|
23
|
+
* 5. ~20 rendered ACTUAL production blocks dumped into the report.
|
|
24
|
+
* 6. Redundancy — one set-level judge call per (prompt × mode) over the
|
|
25
|
+
* production 6.
|
|
26
|
+
* 7. Rate limiting + resumability (§6b, MANDATORY): serial calls,
|
|
27
|
+
* `--judge-delay-ms` (default 2000), exponential backoff with jitter on
|
|
28
|
+
* 429/5xx/timeout (5→10→20→40→80s, max 5 retries, respects
|
|
29
|
+
* `Retry-After`), checkpoint-per-call to a `.jsonl` sidecar, `--resume`,
|
|
30
|
+
* progress logging, 10%-error-rate abort, `--max-calls` budget guard
|
|
31
|
+
* (default 900).
|
|
32
|
+
*
|
|
33
|
+
* Prompt corpus (spec §2, owner decision §11.1): EVEN split, 20 prompts per
|
|
34
|
+
* source × 5 sources — Hermes (lenny, raider, nano) + CC (the DevOps
|
|
35
|
+
* `infrastructure` project, the `aironic-marine` project). Saved to
|
|
36
|
+
* `data/prompts.json`, stable/reused verbatim once a valid v2 set exists.
|
|
37
|
+
*
|
|
38
|
+
* Judge: GLM-5.2 via z.ai — the INSTRUMENT only. It never picks candidates;
|
|
39
|
+
* retrieve() (LLM-free) does. A dedicated raw HTTP caller (NOT `LlmClient`) is
|
|
40
|
+
* used here on purpose: `LlmClient.completeReflect` bakes in a
|
|
41
|
+
* nightly-tolerant retry policy (30s/60s/120s, unlimited rate-limit patience)
|
|
42
|
+
* that conflicts with §6b's specific real-time batch policy (5/10/20/40/80s +
|
|
43
|
+
* jitter, 5 retries, a hard call budget). Implemented directly here rather
|
|
44
|
+
* than adding a second retry mode to `llm.ts` (out of scope for this eval,
|
|
45
|
+
* and another agent is concurrently working elsewhere in this repo).
|
|
46
|
+
*
|
|
47
|
+
* Honesty invariants (non-negotiable — mirror recall-sweep.ts + spec §7):
|
|
48
|
+
* - Snapshot opened READONLY via openSnapshot — never initDb.
|
|
49
|
+
* - noStrengthen: true on every retrieve() call.
|
|
50
|
+
* - Real bge-small-en-v1.5 embedder, embed-once + queryEmbedding reuse.
|
|
51
|
+
* - neverCalledEmbed self-check ABORTS the run if retrieve() ignores
|
|
52
|
+
* queryEmbedding (would invalidate every measured number).
|
|
53
|
+
* - GLM-5.2 is the JUDGE only, real prompts, no synthetic queries.
|
|
54
|
+
* - Production renderer (`formatIndexLine`/`memoryTitle`) imported from
|
|
55
|
+
* `recall-index.ts`, never reimplemented.
|
|
56
|
+
* - judge_error batches/units excluded from every denominator, reported
|
|
57
|
+
* separately.
|
|
58
|
+
*
|
|
59
|
+
* Run:
|
|
60
|
+
* npm run eval:relevance -- <snapshot.db> [prompts.json] [report.md] \
|
|
61
|
+
* [--judge-delay-ms=2000] [--max-calls=900] [--resume] \
|
|
62
|
+
* [--verdicts-json=path] [--verdicts-jsonl=path]
|
|
63
|
+
*/
|
|
64
|
+
export {};
|