@gamaze/hicortex 0.16.7 → 0.16.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 +8 -28
- package/dist/classify-domains.d.ts +12 -13
- package/dist/classify-domains.js +12 -40
- package/dist/consolidate.d.ts +5 -5
- package/dist/consolidate.js +3 -4
- package/dist/distiller.d.ts +12 -4
- package/dist/distiller.js +20 -15
- package/dist/domain-classify.d.ts +7 -7
- package/dist/domain-classify.js +7 -7
- package/dist/features.d.ts +12 -2
- package/dist/features.js +14 -3
- package/dist/index.js +5 -1
- package/dist/init.d.ts +9 -10
- package/dist/init.js +11 -14
- package/dist/lessons-context.d.ts +2 -0
- package/dist/lessons-context.js +8 -2
- package/dist/llm.d.ts +35 -147
- package/dist/llm.js +63 -379
- package/dist/mcp-server.js +12 -52
- package/dist/nightly-status.js +1 -2
- package/dist/nightly.js +19 -48
- package/dist/prompts.d.ts +6 -0
- package/dist/prompts.js +16 -3
- package/dist/telemetry.d.ts +9 -0
- package/dist/telemetry.js +3 -0
- package/dist/types.d.ts +30 -57
- package/package.json +1 -1
package/dist/mcp-server.js
CHANGED
|
@@ -76,8 +76,8 @@ const init_js_1 = require("./init.js");
|
|
|
76
76
|
// ---------------------------------------------------------------------------
|
|
77
77
|
let db = null;
|
|
78
78
|
let llm = null;
|
|
79
|
-
// llmConfig is module-level so the /distill handler can
|
|
80
|
-
//
|
|
79
|
+
// llmConfig is module-level so the /distill handler can read numCtx without
|
|
80
|
+
// re-resolving on every request. null when no LLM is configured.
|
|
81
81
|
let llmConfig = null;
|
|
82
82
|
// One-time-per-process deprecation warning for the `?privacy=` query param
|
|
83
83
|
// (0.16.x: the column is vestigial, never filtered). Old clients/plugins still
|
|
@@ -94,9 +94,6 @@ function warnDeprecatedPrivacyParamIfPresent(query, route) {
|
|
|
94
94
|
`privacy is no longer filtered server-side (the column is vestigial). ` +
|
|
95
95
|
`Use a separate Hicortex server for isolation. (This warning fires once per process.)`);
|
|
96
96
|
}
|
|
97
|
-
// distillFallbackMode controls whether a failed remote distill endpoint causes an
|
|
98
|
-
// immediate abort ("strict", default) or a fallback to the base model ("local").
|
|
99
|
-
let distillFallbackMode = "strict";
|
|
100
97
|
let stateDir = "";
|
|
101
98
|
// Resolved contextClients list (spec §2) — the harness names allowed to inject
|
|
102
99
|
// the standing context layer. Echoed by GET /context so each hook self-gates.
|
|
@@ -374,7 +371,8 @@ async function startServer(options = {}) {
|
|
|
374
371
|
// Named backends (claude-cli, ollama) → immediate config; everything else
|
|
375
372
|
// goes through resolveExplicitLlmConfig which requires a user-chosen provider.
|
|
376
373
|
// If nothing is configured: start recall-only with an unmissable warning.
|
|
377
|
-
|
|
374
|
+
// One model serves all phases (#231) — no per-tier overlay here.
|
|
375
|
+
const savedConfig = readConfigFile(stateDir);
|
|
378
376
|
// 0.16.2 activation gap: self-heal the agentId provenance field for
|
|
379
377
|
// pre-0.16.2 server installs on first boot after upgrade. The server's own
|
|
380
378
|
// nightly captures its sessions to localhost:8787/distill and needs this id;
|
|
@@ -402,7 +400,6 @@ async function startServer(options = {}) {
|
|
|
402
400
|
baseUrl: savedConfig.llmBaseUrl ?? "http://localhost:11434",
|
|
403
401
|
apiKey: "",
|
|
404
402
|
model: savedConfig.llmModel ?? "qwen3.5:4b",
|
|
405
|
-
reflectModel: savedConfig.reflectModel ?? savedConfig.llmModel ?? "qwen3.5:4b",
|
|
406
403
|
provider: "ollama",
|
|
407
404
|
};
|
|
408
405
|
}
|
|
@@ -411,41 +408,15 @@ async function startServer(options = {}) {
|
|
|
411
408
|
llmBaseUrl: savedConfig?.llmBaseUrl,
|
|
412
409
|
llmApiKey: savedConfig?.llmApiKey,
|
|
413
410
|
llmModel: savedConfig?.llmModel,
|
|
414
|
-
reflectModel: savedConfig?.reflectModel,
|
|
415
411
|
});
|
|
416
412
|
}
|
|
417
413
|
if (llmConfig) {
|
|
418
|
-
//
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
}
|
|
422
|
-
if (savedConfig?.distillBaseUrl) {
|
|
423
|
-
llmConfig.distillBaseUrl = savedConfig.distillBaseUrl;
|
|
424
|
-
llmConfig.distillApiKey = savedConfig.distillApiKey ?? llmConfig.apiKey;
|
|
425
|
-
llmConfig.distillProvider = savedConfig.distillProvider ?? llmConfig.provider;
|
|
426
|
-
}
|
|
427
|
-
// Heavy-phase tuning (#220): maxTokens + enableThinking, validated + copied
|
|
428
|
-
// via the shared overlay (also applied in resolveSavedLlmConfig for the
|
|
429
|
-
// nightly's reflect + classify). Wrong-typed values warn + drop.
|
|
414
|
+
// Tuning (#220: maxTokens + enableThinking + numCtx + flush), validated +
|
|
415
|
+
// copied via the shared overlay (also applied in resolveSavedLlmConfig for
|
|
416
|
+
// the nightly). Wrong-typed values warn + drop.
|
|
430
417
|
(0, llm_js_1.applyTierTuningOverlay)(llmConfig, savedConfig);
|
|
431
|
-
// Apply separate reflect endpoint if configured (e.g. remote Ollama with larger model)
|
|
432
|
-
if (savedConfig?.reflectBaseUrl) {
|
|
433
|
-
llmConfig.reflectBaseUrl = savedConfig.reflectBaseUrl;
|
|
434
|
-
llmConfig.reflectApiKey = savedConfig.reflectApiKey ?? llmConfig.apiKey;
|
|
435
|
-
llmConfig.reflectProvider = savedConfig.reflectProvider ?? llmConfig.provider;
|
|
436
|
-
}
|
|
437
|
-
// distillFallback: "strict" (default) aborts on remote failure so the session
|
|
438
|
-
// is retried next run. "local" restores 0.9.0 fallback-to-base-model behavior.
|
|
439
|
-
const df = savedConfig?.distillFallback;
|
|
440
|
-
distillFallbackMode = df === "local" ? "local" : "strict";
|
|
441
418
|
llm = new llm_js_1.LlmClient(llmConfig);
|
|
442
|
-
|
|
443
|
-
? `${llmConfig.distillProvider}/${llmConfig.distillModel}@${llmConfig.distillBaseUrl}`
|
|
444
|
-
: llmConfig.distillModel ? llmConfig.distillModel : "";
|
|
445
|
-
const reflectInfo = llmConfig.reflectBaseUrl
|
|
446
|
-
? `${llmConfig.reflectProvider}/${llmConfig.reflectModel}@${llmConfig.reflectBaseUrl}`
|
|
447
|
-
: llmConfig.reflectModel;
|
|
448
|
-
console.log(`[hicortex] LLM fast: ${llmConfig.provider}/${llmConfig.model}${distillInfo ? `, distill: ${distillInfo}` : ""}, reflect: ${reflectInfo}`);
|
|
419
|
+
console.log(`[hicortex] LLM (one model, all phases): ${llmConfig.provider}/${llmConfig.model}`);
|
|
449
420
|
}
|
|
450
421
|
else {
|
|
451
422
|
llm = null;
|
|
@@ -884,23 +855,12 @@ async function startServer(options = {}) {
|
|
|
884
855
|
return;
|
|
885
856
|
}
|
|
886
857
|
}
|
|
887
|
-
// Pre-flight the distill endpoint. In strict mode (default) a failed remote
|
|
888
|
-
// probe returns "abort" immediately without mutating llmConfig — the nightly
|
|
889
|
-
// watermark stays put so the session is re-shipped next run. In "local" mode
|
|
890
|
-
// the config is mutated to fall back to the base model.
|
|
891
|
-
const cfg = llmConfig;
|
|
892
|
-
const distillFallbackStatus = await (0, llm_js_1.resolveDistillFallback)(cfg, distillFallbackMode);
|
|
893
|
-
if (distillFallbackStatus === "abort") {
|
|
894
|
-
res.status(503).json({ error: "Distill endpoint unavailable — session will be retried next run" });
|
|
895
|
-
return;
|
|
896
|
-
}
|
|
897
858
|
// Cache detectChunkSize per endpoint so we probe at most once per server boot.
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
const
|
|
901
|
-
const cacheKey = `${effectiveProvider}/${effectiveModel}@${effectiveBaseUrl}`;
|
|
859
|
+
// numCtx is passed so chunk size derives from the request's ACTUAL context
|
|
860
|
+
// window (#231, #228) — the chunker and the request agree by construction.
|
|
861
|
+
const cacheKey = `${llmConfig.provider}/${llmConfig.model}@${llmConfig.baseUrl}`;
|
|
902
862
|
if (!chunkSizeCache.has(cacheKey)) {
|
|
903
|
-
chunkSizeCache.set(cacheKey, await (0, distiller_js_1.detectChunkSize)(
|
|
863
|
+
chunkSizeCache.set(cacheKey, await (0, distiller_js_1.detectChunkSize)(llmConfig.provider, llmConfig.model, llmConfig.baseUrl, llmConfig.numCtx));
|
|
904
864
|
}
|
|
905
865
|
const chunkSize = chunkSizeCache.get(cacheKey);
|
|
906
866
|
const date = typeof session_date === "string" && session_date ? session_date : new Date().toISOString().slice(0, 10);
|
package/dist/nightly-status.js
CHANGED
|
@@ -18,7 +18,6 @@ const node_os_1 = require("node:os");
|
|
|
18
18
|
const node_child_process_1 = require("node:child_process");
|
|
19
19
|
const db_js_1 = require("./db.js");
|
|
20
20
|
const state_js_1 = require("./state.js");
|
|
21
|
-
const llm_js_1 = require("./llm.js");
|
|
22
21
|
const HICORTEX_HOME = (0, paths_js_1.hicortexHome)();
|
|
23
22
|
const CONFIG_PATH = (0, node_path_1.join)(HICORTEX_HOME, "config.json");
|
|
24
23
|
async function showNightlyStatus() {
|
|
@@ -39,7 +38,7 @@ async function showNightlyStatus() {
|
|
|
39
38
|
try {
|
|
40
39
|
// No `?? {}` coercion: a null/invalid parse must fall through to the catch
|
|
41
40
|
// below (as it did pre-0.13.1) rather than print a fabricated-healthy status.
|
|
42
|
-
const config =
|
|
41
|
+
const config = JSON.parse((0, node_fs_1.readFileSync)(CONFIG_PATH, "utf-8"));
|
|
43
42
|
const backend = config.llmBackend ?? "auto-detect";
|
|
44
43
|
const model = config.llmModel ?? "default";
|
|
45
44
|
const mode = config.mode === "client" ? "client → " + (config.serverUrl ?? "?") : "server (local)";
|
package/dist/nightly.js
CHANGED
|
@@ -366,62 +366,24 @@ async function runNightly(options = {}) {
|
|
|
366
366
|
// Runs even if capture had transient failures (opens DB directly, independent
|
|
367
367
|
// of the HTTP capture path). Full nightly only — capture-only runs are
|
|
368
368
|
// intended to run more frequently than once daily.
|
|
369
|
+
let lessonsGenerated; // hoisted for telemetry; undefined when reflection didn't run (skipped) — bucketed apart from a real 0
|
|
369
370
|
if (!dryRun && !captureOnly) {
|
|
370
371
|
if (!llm || !llmConfig) {
|
|
371
372
|
console.error("[hicortex] consolidation skipped: no LLM configured — run npx @gamaze/hicortex init");
|
|
372
373
|
}
|
|
373
374
|
else {
|
|
374
|
-
//
|
|
375
|
-
// If
|
|
376
|
-
//
|
|
377
|
-
//
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
const health = await (0, llm_js_1.probeOllamaModel)(llmConfig.reflectBaseUrl, reflectModel);
|
|
382
|
-
if (!health.ok) {
|
|
383
|
-
const reason = health.reason === "unreachable"
|
|
384
|
-
? `reflect endpoint unreachable (${llmConfig.reflectBaseUrl})`
|
|
385
|
-
: `reflect model not loaded (${reflectModel} missing on ${llmConfig.reflectBaseUrl})`;
|
|
386
|
-
console.warn(`[hicortex] ${reason} — skipping reflection, scoring + linking will still run`);
|
|
387
|
-
skipReflection = true;
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
// Content-based domain classification (config-owned `domains`) uses
|
|
391
|
-
// the classify tier (classifyModel/classifyBaseUrl) when configured,
|
|
392
|
-
// else the reflect tier. Pre-flight the endpoint classification will
|
|
393
|
-
// ACTUALLY use (resolveClassifyProbeTarget is the shared source of
|
|
394
|
-
// truth with `hicortex classify-domains`). If it is down, content
|
|
395
|
-
// classification is NOT ready this run (strict — skip, don't fall
|
|
396
|
-
// back). When no `domains` list is configured, this is inert and the
|
|
397
|
-
// legacy project-grouping path runs.
|
|
375
|
+
// One model serves all phases (#231) — there is no separate endpoint to
|
|
376
|
+
// pre-flight. If the model doesn't answer, `complete()` already retries at
|
|
377
|
+
// 30s/60s/120s (~3.5 min); anything still failing after that is an outage,
|
|
378
|
+
// not a blip. A failed phase costs latency, not data: capture cursors hold
|
|
379
|
+
// on failure (dup-over-loss), and consolidation has resumable cursors
|
|
380
|
+
// (domainCursor, supersessionCursor). The nightly runs 2-4×/day, so the
|
|
381
|
+
// wait is hours — no polling, no new config. (Issue #231.)
|
|
398
382
|
const cfgDomains = (0, domain_classify_js_1.parseConfigDomains)(savedConfig);
|
|
399
|
-
let contentDomainsReady = true;
|
|
400
|
-
if (cfgDomains) {
|
|
401
|
-
const classifyTarget = (0, llm_js_1.resolveClassifyProbeTarget)(llmConfig);
|
|
402
|
-
if (classifyTarget?.tier === "reflect") {
|
|
403
|
-
// Classification rides the reflect endpoint — reuse the probe above.
|
|
404
|
-
contentDomainsReady = !skipReflection;
|
|
405
|
-
}
|
|
406
|
-
else if (classifyTarget) {
|
|
407
|
-
const health = await (0, llm_js_1.probeOllamaModel)(classifyTarget.baseUrl, classifyTarget.model);
|
|
408
|
-
if (!health.ok) {
|
|
409
|
-
const reason = health.reason === "unreachable"
|
|
410
|
-
? `classify endpoint unreachable (${classifyTarget.baseUrl})`
|
|
411
|
-
: `classify model not loaded (${classifyTarget.model} missing on ${classifyTarget.baseUrl})`;
|
|
412
|
-
console.warn(`[hicortex] ${reason}`);
|
|
413
|
-
contentDomainsReady = false;
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
// classifyTarget === null → base endpoint or API provider, no probe.
|
|
417
|
-
if (!contentDomainsReady) {
|
|
418
|
-
console.warn("[hicortex] content-domain classification skipped — classification endpoint offline (strict)");
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
383
|
console.log(`[hicortex] Running consolidation...`);
|
|
422
|
-
const report = await (0, consolidate_js_1.runConsolidation)(db, llm, embedder_js_1.embed, dryRun,
|
|
384
|
+
const report = await (0, consolidate_js_1.runConsolidation)(db, llm, embedder_js_1.embed, dryRun, false, undefined, {
|
|
423
385
|
domains: cfgDomains,
|
|
424
|
-
contentDomainsReady,
|
|
386
|
+
contentDomainsReady: true,
|
|
425
387
|
weakPrimaryFloor: (0, nofit_js_1.resolveWeakPrimaryFloor)(savedConfig),
|
|
426
388
|
}, {
|
|
427
389
|
minSimilarity: savedConfig?.supersessionMinSimilarity,
|
|
@@ -429,6 +391,14 @@ async function runNightly(options = {}) {
|
|
|
429
391
|
});
|
|
430
392
|
console.log(`[hicortex] Consolidation ${report.status} in ${report.elapsed_seconds}s` +
|
|
431
393
|
(report.stages.reflection ? ` (${report.stages.reflection.lessons_generated} lessons)` : ""));
|
|
394
|
+
// Only set when reflection actually RAN (not skipped). A skipped stage
|
|
395
|
+
// (e.g. endpoint offline, #232 fail-soft) must NOT collapse to 0 — that
|
|
396
|
+
// would make "endpoint down" indistinguishable from "prompt too tight"
|
|
397
|
+
// in the fleet aggregate. Leave undefined so the optional field is
|
|
398
|
+
// omitted and the aggregate buckets skipped runs separately.
|
|
399
|
+
const refl = report.stages.reflection;
|
|
400
|
+
if (refl && !refl.skipped)
|
|
401
|
+
lessonsGenerated = refl.lessons_generated;
|
|
432
402
|
}
|
|
433
403
|
}
|
|
434
404
|
// Step 4: Update last-run timestamp.
|
|
@@ -473,6 +443,7 @@ async function runNightly(options = {}) {
|
|
|
473
443
|
agent: agentType,
|
|
474
444
|
mem: storage.countMemories(db),
|
|
475
445
|
lessons: storage.getLessons(db, 365).length,
|
|
446
|
+
lessonsGenerated,
|
|
476
447
|
sessions: batches.length,
|
|
477
448
|
ok: !hadTransientFailure,
|
|
478
449
|
shown: adoption.shown,
|
package/dist/prompts.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* LLM prompt templates for memory consolidation and distillation.
|
|
3
3
|
* Copied EXACTLY from the Python codebase (proven working prompts).
|
|
4
|
+
*
|
|
5
|
+
* SHIPPED SOURCE: this file is compiled into dist/ and published to npm + the
|
|
6
|
+
* public mirror (it is NOT in .publicignore). Any example, name, or detail in
|
|
7
|
+
* these prompts is therefore public. Use generic, anonymous examples — never
|
|
8
|
+
* real internal project/tool/host names or real incident specifics. The
|
|
9
|
+
* infra-name denylist cannot catch conceptual leaks, only known names.
|
|
4
10
|
*/
|
|
5
11
|
/**
|
|
6
12
|
* Importance scoring prompt. Takes a {memories_block} with indexed memories.
|
package/dist/prompts.js
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* LLM prompt templates for memory consolidation and distillation.
|
|
4
4
|
* Copied EXACTLY from the Python codebase (proven working prompts).
|
|
5
|
+
*
|
|
6
|
+
* SHIPPED SOURCE: this file is compiled into dist/ and published to npm + the
|
|
7
|
+
* public mirror (it is NOT in .publicignore). Any example, name, or detail in
|
|
8
|
+
* these prompts is therefore public. Use generic, anonymous examples — never
|
|
9
|
+
* real internal project/tool/host names or real incident specifics. The
|
|
10
|
+
* infra-name denylist cannot catch conceptual leaks, only known names.
|
|
5
11
|
*/
|
|
6
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
13
|
exports.importanceScoring = importanceScoring;
|
|
@@ -41,6 +47,9 @@ function reflection(memoriesBlock, recentLessons) {
|
|
|
41
47
|
|
|
42
48
|
Like human learning: we grow fastest when we reinforce what works AND correct what doesn't. A system that only learns from mistakes becomes overly cautious. A system that only learns from successes never improves. The combination multiplies.
|
|
43
49
|
|
|
50
|
+
GENERALITY BAR (read carefully — the most important rule):
|
|
51
|
+
Every lesson MUST be a generalizable operating principle that transfers across contexts, agents, and projects. It is NOT: an incident report, a changelog entry, a one-event fact, a tool-specific recipe, or a note about a named entity. If a memory is only interesting as "what happened today", it is an EPISODE — do not emit a lesson for it. Abstract away specific tool names, hostnames, and incident details from the lesson text; state the transferable rule.
|
|
52
|
+
|
|
44
53
|
Quality over quantity. 1-3 lessons is typical. An empty array [] is the CORRECT response when memories show routine competent work without noteworthy patterns, surprises, or friction. Do not manufacture lessons from nothing.
|
|
45
54
|
|
|
46
55
|
LESSON TYPES:
|
|
@@ -56,15 +65,19 @@ Good reinforce: "Bundling related changes into a single PR with clear narrative
|
|
|
56
65
|
Good reinforce: "When presenting multi-scenario analysis, show assumptions side-by-side so stakeholders evaluate trade-offs rather than reacting to isolated worst-cases"
|
|
57
66
|
Good correct: "Always verify ALL substitution targets by diffing output — partial fixes cause silent failures"
|
|
58
67
|
Good principle: "Gather evidence from logs before forming hypotheses — evidence-first debugging resolved issues 3x faster today"
|
|
68
|
+
Good principle: "When a long-running background agent survives a system migration as an orphan, explicitly unregister it before declaring the migration clean — orphans cause silent crash-loops"
|
|
59
69
|
Bad lesson: "The deploy script had a bug" (restatement, not actionable)
|
|
70
|
+
Bad (incident note / changelog entry): "The graph resolver was fixed by adding a computed-at marker column" — that is a changelog entry, not a lesson
|
|
71
|
+
Bad (tool-specific decision): "Tool X is banned because it broke Tool Y's settings" — a one-tool decision, not transferable
|
|
72
|
+
Bad (single-event): "The chat client crashed after a system restore because a background agent was left orphaned" — an incident report, not a principle
|
|
60
73
|
|
|
61
74
|
For each lesson, output a JSON object:
|
|
62
|
-
- "lesson": Concise, actionable rule in imperative voice
|
|
75
|
+
- "lesson": Concise, actionable rule in imperative voice. State the transferable rule — abstract away specific tool names, hostnames, and incident details.
|
|
63
76
|
- "type": "reinforce" | "correct" | "principle"
|
|
64
77
|
- "project": "global" unless genuinely project-specific (project-specific lessons are still valuable)
|
|
65
78
|
- "severity": "critical" | "important" | "minor"
|
|
66
79
|
- "confidence": "high" | "medium" | "low"
|
|
67
|
-
- "source_pattern": What triggered this (1 sentence, no personal data)
|
|
80
|
+
- "source_pattern": What triggered this (1 sentence, no personal data; may name the specific incident/tool here — but the \`lesson\` field itself stays generic)
|
|
68
81
|
|
|
69
82
|
Severity guide:
|
|
70
83
|
- "critical": Near-misses that could have caused data loss or security breach, even if caught in time. Also: recurring patterns that keep appearing despite prior corrections.
|
|
@@ -87,7 +100,7 @@ Focus on:
|
|
|
87
100
|
|
|
88
101
|
Privacy: Never include personal data (names, health, finances, credentials) in lesson text. Abstract to the process level.
|
|
89
102
|
|
|
90
|
-
Skip: isolated trivial actions, already-documented rules. However, if multiple small successes form a consistent pattern of quality, extract that pattern as a reinforcement.
|
|
103
|
+
Skip: isolated trivial actions, already-documented rules, incident notes, changelog entries, and tool-specific recipes. However, if multiple small successes form a consistent pattern of quality, extract that pattern as a reinforcement.
|
|
91
104
|
|
|
92
105
|
Respond with a JSON array. Empty array [] is a valid response.`;
|
|
93
106
|
}
|
package/dist/telemetry.d.ts
CHANGED
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
* client is never miscounted as "cc".
|
|
14
14
|
* mem — total memory count
|
|
15
15
|
* lessons — total lesson count
|
|
16
|
+
* lessonsGenerated — lessons created THIS run (server mode only; the per-run
|
|
17
|
+
* delta, distinct from `lessons` which is the corpus total). Lets a
|
|
18
|
+
* silent decline in reflection output be seen in the fleet aggregate.
|
|
16
19
|
* sessions — sessions distilled this run
|
|
17
20
|
* ok — nightly succeeded (true/false)
|
|
18
21
|
* shown — sum of shown_count (server mode only)
|
|
@@ -76,6 +79,12 @@ export interface TelemetryPayload {
|
|
|
76
79
|
shown?: number;
|
|
77
80
|
uses?: number;
|
|
78
81
|
cold?: number;
|
|
82
|
+
/**
|
|
83
|
+
* Lessons generated THIS run (server mode only). The per-run delta —
|
|
84
|
+
* `lessons` above is the corpus total, which drifts slowly via decay/prune
|
|
85
|
+
* and can't reveal a sudden drop in reflection output. 0.16.9+.
|
|
86
|
+
*/
|
|
87
|
+
lessonsGenerated?: number;
|
|
79
88
|
}
|
|
80
89
|
/**
|
|
81
90
|
* Check if telemetry is enabled. Disabled by:
|
package/dist/telemetry.js
CHANGED
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
* client is never miscounted as "cc".
|
|
15
15
|
* mem — total memory count
|
|
16
16
|
* lessons — total lesson count
|
|
17
|
+
* lessonsGenerated — lessons created THIS run (server mode only; the per-run
|
|
18
|
+
* delta, distinct from `lessons` which is the corpus total). Lets a
|
|
19
|
+
* silent decline in reflection output be seen in the fleet aggregate.
|
|
17
20
|
* sessions — sessions distilled this run
|
|
18
21
|
* ok — nightly succeeded (true/false)
|
|
19
22
|
* shown — sum of shown_count (server mode only)
|
package/dist/types.d.ts
CHANGED
|
@@ -154,16 +154,6 @@ export interface ConsolidationReport {
|
|
|
154
154
|
calls_by_stage: Record<string, number>;
|
|
155
155
|
};
|
|
156
156
|
}
|
|
157
|
-
/**
|
|
158
|
-
* A single per-stage override inside the nested `models` server-config block.
|
|
159
|
-
* Consumed by `applyModelsBlock` (llm.ts), which re-exports this type.
|
|
160
|
-
*/
|
|
161
|
-
export interface ModelTierOverride {
|
|
162
|
-
model?: string;
|
|
163
|
-
baseUrl?: string;
|
|
164
|
-
apiKey?: string;
|
|
165
|
-
provider?: string;
|
|
166
|
-
}
|
|
167
157
|
/** Plugin configuration from openclaw.plugin.json configSchema. */
|
|
168
158
|
export interface HicortexConfig {
|
|
169
159
|
licenseKey?: string;
|
|
@@ -186,33 +176,6 @@ export interface HicortexConfig {
|
|
|
186
176
|
llmApiKey?: string;
|
|
187
177
|
/** @deprecated Use the Hicortex server for distillation and consolidation. */
|
|
188
178
|
llmModel?: string;
|
|
189
|
-
/** @deprecated Use the Hicortex server for distillation and consolidation. */
|
|
190
|
-
reflectModel?: string;
|
|
191
|
-
/**
|
|
192
|
-
* Optional dedicated model for memory tag classification (server-side
|
|
193
|
-
* nightly + `hicortex classify-domains`). When unset, classification uses
|
|
194
|
-
* the reflect tier exactly as before.
|
|
195
|
-
*/
|
|
196
|
-
classifyModel?: string;
|
|
197
|
-
/**
|
|
198
|
-
* Optional dedicated endpoint for classification. When only classifyModel
|
|
199
|
-
* is set, it runs on the reflect endpoint (else the base endpoint).
|
|
200
|
-
*/
|
|
201
|
-
classifyBaseUrl?: string;
|
|
202
|
-
/** Optional API key for the classify endpoint (defaults to the base apiKey). */
|
|
203
|
-
classifyApiKey?: string;
|
|
204
|
-
/** Optional provider for the classify endpoint (defaults to the base provider). */
|
|
205
|
-
classifyProvider?: string;
|
|
206
|
-
/**
|
|
207
|
-
* Server config (NOT an OC-plugin key): nested per-stage model overrides.
|
|
208
|
-
* `{ score|distill|reflect|classify: { model?, baseUrl?, apiKey?, provider? } }`.
|
|
209
|
-
* Normalized onto the flat `llm*` / `distill*` / `reflect*` / `classify*`
|
|
210
|
-
* keys at read time (see applyModelsBlock in llm.ts); nested wins, and the
|
|
211
|
-
* flat keys remain supported at lower precedence. Happy path is a single model via
|
|
212
|
-
* `llmModel`; use this block only for per-stage routing. `score.provider` is
|
|
213
|
-
* ignored (base provider comes from llmBackend).
|
|
214
|
-
*/
|
|
215
|
-
models?: Record<string, ModelTierOverride>;
|
|
216
179
|
/** @deprecated Consolidation is owned by the server nightly. */
|
|
217
180
|
consolidateHour?: number;
|
|
218
181
|
/** @deprecated The OC plugin no longer opens its own database. */
|
|
@@ -283,34 +246,37 @@ export interface HicortexConfig {
|
|
|
283
246
|
*/
|
|
284
247
|
preflightRetryGapMs?: number;
|
|
285
248
|
/**
|
|
286
|
-
* Max output tokens for the LLM phases — distillation,
|
|
287
|
-
* and scoring
|
|
288
|
-
*
|
|
289
|
-
*
|
|
290
|
-
* at the model's natural end (finish_reason stop), so a higher cap costs no latency
|
|
249
|
+
* Max output tokens for the ONE LLM model used by all phases — distillation,
|
|
250
|
+
* reflection, classification, and scoring. Default 8192. An explicit value
|
|
251
|
+
* overrides the default. A ceiling, not a target: generation stops at the
|
|
252
|
+
* model's natural end (finish_reason stop), so a higher cap costs no latency
|
|
291
253
|
* when it finishes early. Read in llm.ts; see #220.
|
|
292
254
|
*/
|
|
293
255
|
maxTokens?: number;
|
|
294
256
|
/**
|
|
295
257
|
* Toggle the model's internal reasoning ("thinking") stream on the openai-compat
|
|
296
|
-
* path — applies to
|
|
297
|
-
*
|
|
298
|
-
*
|
|
299
|
-
*
|
|
300
|
-
*
|
|
301
|
-
*
|
|
302
|
-
*
|
|
303
|
-
*
|
|
258
|
+
* path — applies to ALL phases (distill / reflect / classify / scoring) since one
|
|
259
|
+
* model serves all of them. Default false. A thinking model with thinking ON can
|
|
260
|
+
* burn the entire token budget on an unclosed <think> block and emit nothing
|
|
261
|
+
* (probed 2026-08-04). When set (true or false), completeOpenAiCompat sends
|
|
262
|
+
* chat_template_kwargs:{enable_thinking}. LOCAL-ENDPOINT ONLY: this is meaningful
|
|
263
|
+
* only for a chat-template-aware server (ollama, mlx-lm). If the one model is a
|
|
264
|
+
* cloud OpenAI-compatible endpoint (OpenAI / OpenRouter / Groq / z.ai), LEAVE THIS
|
|
265
|
+
* UNSET — the non-standard chat_template_kwargs field rides every call and can 400
|
|
266
|
+
* the whole pipeline (provider cannot distinguish MLX-gateway-as-openai from real
|
|
267
|
+
* cloud openai, so the gate must be operator-set, not detected). No effect on the
|
|
268
|
+
* anthropic or claude-cli paths. See #220, #231.
|
|
304
269
|
*/
|
|
305
270
|
enableThinking?: boolean;
|
|
306
271
|
/**
|
|
307
|
-
* Context window for the
|
|
308
|
-
*
|
|
309
|
-
*
|
|
310
|
-
*
|
|
311
|
-
*
|
|
312
|
-
*
|
|
313
|
-
*
|
|
272
|
+
* Context window for ollama (the one model, all phases). Default 8192 — the point
|
|
273
|
+
* where context stops being the binding constraint for a sub-8B model on ollama
|
|
274
|
+
* (above it the SMALL_MODEL_MAX_CHUNK_CHARS speed cap binds instead, so extra
|
|
275
|
+
* context buys nothing). Also drives `detectChunkSize`'s chunk sizing
|
|
276
|
+
* (chunkChars ≤ numCtx × 0.6 × 4 chars), so numCtx is the single dial and the
|
|
277
|
+
* chunker/request agreement is enforced by construction (#228). For an ≥8B model
|
|
278
|
+
* on ollama the speed cap is 60,000 chars, needing numCtx ≈ 25000 to reach — raise
|
|
279
|
+
* it if running 8B+ locally. No effect for non-ollama providers.
|
|
314
280
|
*/
|
|
315
281
|
numCtx?: number;
|
|
316
282
|
/**
|
|
@@ -334,6 +300,13 @@ export interface HicortexConfig {
|
|
|
334
300
|
* doubled for margin). Only relevant when `ollamaFlushEvery` > 0.
|
|
335
301
|
*/
|
|
336
302
|
ollamaFlushWaitMs?: number;
|
|
303
|
+
/**
|
|
304
|
+
* Max lessons injected into an agent's session-start context (default 10).
|
|
305
|
+
* Lessons are ranked per-session by project/domain affinity + recency +
|
|
306
|
+
* strength + access, so each session sees its most-relevant slice. Lower =
|
|
307
|
+
* leaner system prompts.
|
|
308
|
+
*/
|
|
309
|
+
lessonsLimit?: number;
|
|
337
310
|
}
|
|
338
311
|
/** A config-owned life-sphere domain (see HicortexConfig.domains). */
|
|
339
312
|
export interface DomainDef {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gamaze/hicortex",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.9",
|
|
4
4
|
"description": "Self-learning memory for AI agents — experience captured automatically, distilled into lessons overnight, shared across your whole fleet. Works with Hermes, OpenClaw, Claude Code, and Pi.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|