@gamaze/hicortex 0.16.8 → 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 +1 -0
- package/dist/features.d.ts +12 -2
- package/dist/features.js +14 -3
- package/dist/index.js +5 -1
- package/dist/lessons-context.d.ts +2 -0
- package/dist/lessons-context.js +8 -2
- package/dist/nightly.js +10 -0
- 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 +7 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -211,6 +211,7 @@ Config at `~/.hicortex/config.json`. Created by `init`. Key options:
|
|
|
211
211
|
| `domains` | Your memory domain list (`[{name, description}]`). Scaffolded by `init`; edit freely — see [Memory Domains & Tags](#memory-domains--tags) |
|
|
212
212
|
| `weakPrimaryFloor` | Minimum similarity for a no-fit memory to keep a weak domain association (default: 0.45) |
|
|
213
213
|
| `moduleIndexTokenBudget` | Max tokens for domain index in lessons context (default: 500) |
|
|
214
|
+
| `lessonsLimit` | Max lessons injected into an agent's session-start context (default: 10). Lessons are ranked per session by project/domain affinity + recency + strength + access, so each session sees its most-relevant slice. Lower = leaner system prompts. |
|
|
214
215
|
| `contextClients` | Which harnesses inject the [context layer](#context-layer) at session start (default `["cc"]`; `"all"` or any subset of `cc`/`hermes`/`oc`) |
|
|
215
216
|
| `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) |
|
|
216
217
|
| `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 |
|
package/dist/features.d.ts
CHANGED
|
@@ -25,8 +25,18 @@ export declare function isPro(): boolean;
|
|
|
25
25
|
export declare function maxMemoriesAllowed(): number;
|
|
26
26
|
/** Always false — no cap is ever reached. */
|
|
27
27
|
export declare function memoryCapReached(_currentCount: number): boolean;
|
|
28
|
-
/**
|
|
29
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Max lessons injected into an agent's session-start context. Configurable via
|
|
30
|
+
* `config.lessonsLimit` (a positive integer); defaults to 10. Reuses
|
|
31
|
+
* `readPositiveConfig` so a present-but-invalid value (0, negative, NaN, wrong
|
|
32
|
+
* type) is rejected AT THE BOUNDARY with a warn — never silently. 0 is NOT
|
|
33
|
+
* honoured as "off" (use a real config switch if that's ever needed); it is
|
|
34
|
+
* invalid and falls back to 10 with a warning, so an operator can't
|
|
35
|
+
* accidentally silence lesson injection by typing 0.
|
|
36
|
+
*/
|
|
37
|
+
export declare function lessonsLimit(config?: {
|
|
38
|
+
lessonsLimit?: unknown;
|
|
39
|
+
} | null): number;
|
|
30
40
|
/** Always true — remote ingest is always allowed. */
|
|
31
41
|
export declare function remoteIngestAllowed(): boolean;
|
|
32
42
|
/** Direct read of the underlying features record. */
|
package/dist/features.js
CHANGED
|
@@ -24,6 +24,7 @@ exports.getCurrentFeatures = getCurrentFeatures;
|
|
|
24
24
|
const paths_js_1 = require("./paths.js");
|
|
25
25
|
const license_js_1 = require("./license.js");
|
|
26
26
|
const state_js_1 = require("./state.js");
|
|
27
|
+
const config_read_js_1 = require("./config-read.js");
|
|
27
28
|
const DEFAULT_STATE_DIR = (0, paths_js_1.hicortexHome)();
|
|
28
29
|
// A single canonical "full" feature set — no tiers.
|
|
29
30
|
const FULL_FEATURES = {
|
|
@@ -90,9 +91,19 @@ function maxMemoriesAllowed() {
|
|
|
90
91
|
function memoryCapReached(_currentCount) {
|
|
91
92
|
return false;
|
|
92
93
|
}
|
|
93
|
-
/**
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
/**
|
|
95
|
+
* Max lessons injected into an agent's session-start context. Configurable via
|
|
96
|
+
* `config.lessonsLimit` (a positive integer); defaults to 10. Reuses
|
|
97
|
+
* `readPositiveConfig` so a present-but-invalid value (0, negative, NaN, wrong
|
|
98
|
+
* type) is rejected AT THE BOUNDARY with a warn — never silently. 0 is NOT
|
|
99
|
+
* honoured as "off" (use a real config switch if that's ever needed); it is
|
|
100
|
+
* invalid and falls back to 10 with a warning, so an operator can't
|
|
101
|
+
* accidentally silence lesson injection by typing 0.
|
|
102
|
+
*/
|
|
103
|
+
function lessonsLimit(config) {
|
|
104
|
+
if (!config)
|
|
105
|
+
return 10;
|
|
106
|
+
return Math.floor((0, config_read_js_1.readPositiveConfig)({ lessonsLimit: config.lessonsLimit }, "lessonsLimit", 10));
|
|
96
107
|
}
|
|
97
108
|
/** Always true — remote ingest is always allowed. */
|
|
98
109
|
function remoteIngestAllowed() {
|
package/dist/index.js
CHANGED
|
@@ -50,6 +50,9 @@ const THIS_HARNESS = "oc";
|
|
|
50
50
|
let serverUrl = DEFAULT_SERVER_URL;
|
|
51
51
|
let authToken;
|
|
52
52
|
let hicortexHome = HICORTEX_HOME;
|
|
53
|
+
/** Resolved plugin config captured at service start — used for tunable knobs
|
|
54
|
+
* (e.g. lessonsLimit) that injected context blocks read at hook time. */
|
|
55
|
+
let pluginConfig = null;
|
|
53
56
|
/** Old-server guard (F2): 0 = not latched; otherwise the Date.now() epoch-ms
|
|
54
57
|
* until which /recall-index is skipped after a 404 (pre-0.14 server). The
|
|
55
58
|
* latch EXPIRES so a client-first rollout heals itself once the server is
|
|
@@ -152,7 +155,7 @@ async function buildLessonsBlock(project) {
|
|
|
152
155
|
const { data } = await serverGet("/lessons", LESSONS_TIMEOUT_MS);
|
|
153
156
|
if (!data || !data.lessons || data.lessons.length === 0)
|
|
154
157
|
return null;
|
|
155
|
-
const maxLessons = (0, features_js_1.lessonsLimit)();
|
|
158
|
+
const maxLessons = (0, features_js_1.lessonsLimit)(pluginConfig);
|
|
156
159
|
const state = (0, state_js_1.loadState)(hicortexHome);
|
|
157
160
|
const moduleIndex = data.moduleIndex ?? state.moduleIndex;
|
|
158
161
|
const selected = await (0, extensions_js_1.getLessonSelector)().select(data.lessons, {
|
|
@@ -264,6 +267,7 @@ exports.default = {
|
|
|
264
267
|
id: "hicortex-service",
|
|
265
268
|
async start(ctx) {
|
|
266
269
|
const config = (ctx.config ?? {});
|
|
270
|
+
pluginConfig = config;
|
|
267
271
|
const log = ctx.logger
|
|
268
272
|
? (msg) => ctx.logger.info(msg)
|
|
269
273
|
: console.log;
|
|
@@ -39,6 +39,8 @@ export interface ResolvedConfig {
|
|
|
39
39
|
home: string;
|
|
40
40
|
/** Per-agent context id sent as ?agent= (0.13); null → global (no param). */
|
|
41
41
|
agentName: string | null;
|
|
42
|
+
/** Max lessons to inject (config.lessonsLimit, default 10). */
|
|
43
|
+
lessonsLimit?: number;
|
|
42
44
|
}
|
|
43
45
|
/**
|
|
44
46
|
* Read ~/.hicortex/config.json and resolve the server URL + auth token, or
|
package/dist/lessons-context.js
CHANGED
|
@@ -64,7 +64,13 @@ function resolveConfig() {
|
|
|
64
64
|
// context. A configured agentName that sanitizes to null → agentId null too
|
|
65
65
|
// (NO ?agent=), never a 400 that the fail-soft hook would silently swallow.
|
|
66
66
|
const agentName = (0, context_store_js_1.resolveAgentIdentity)(config).agentId;
|
|
67
|
-
return {
|
|
67
|
+
return {
|
|
68
|
+
serverUrl,
|
|
69
|
+
authToken: config.authToken,
|
|
70
|
+
home,
|
|
71
|
+
agentName,
|
|
72
|
+
lessonsLimit: typeof config.lessonsLimit === "number" ? config.lessonsLimit : undefined,
|
|
73
|
+
};
|
|
68
74
|
}
|
|
69
75
|
function authHeaders(authToken) {
|
|
70
76
|
return authToken ? { "Authorization": `Bearer ${authToken}` } : {};
|
|
@@ -81,7 +87,7 @@ async function fetchLessonsBlock(cfg) {
|
|
|
81
87
|
if (!resp.ok)
|
|
82
88
|
return null;
|
|
83
89
|
const data = await resp.json();
|
|
84
|
-
const maxLessons = (0, features_js_1.lessonsLimit)();
|
|
90
|
+
const maxLessons = (0, features_js_1.lessonsLimit)(cfg);
|
|
85
91
|
const moduleIndex = data.moduleIndex ?? (0, state_js_1.loadState)(cfg.home).moduleIndex;
|
|
86
92
|
// The SessionStart hook runs in the session's working directory, whose last
|
|
87
93
|
// path component matches the capture-side CC project name convention
|
package/dist/nightly.js
CHANGED
|
@@ -366,6 +366,7 @@ 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");
|
|
@@ -390,6 +391,14 @@ async function runNightly(options = {}) {
|
|
|
390
391
|
});
|
|
391
392
|
console.log(`[hicortex] Consolidation ${report.status} in ${report.elapsed_seconds}s` +
|
|
392
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;
|
|
393
402
|
}
|
|
394
403
|
}
|
|
395
404
|
// Step 4: Update last-run timestamp.
|
|
@@ -434,6 +443,7 @@ async function runNightly(options = {}) {
|
|
|
434
443
|
agent: agentType,
|
|
435
444
|
mem: storage.countMemories(db),
|
|
436
445
|
lessons: storage.getLessons(db, 365).length,
|
|
446
|
+
lessonsGenerated,
|
|
437
447
|
sessions: batches.length,
|
|
438
448
|
ok: !hadTransientFailure,
|
|
439
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
|
@@ -300,6 +300,13 @@ export interface HicortexConfig {
|
|
|
300
300
|
* doubled for margin). Only relevant when `ollamaFlushEvery` > 0.
|
|
301
301
|
*/
|
|
302
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;
|
|
303
310
|
}
|
|
304
311
|
/** A config-owned life-sphere domain (see HicortexConfig.domains). */
|
|
305
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": {
|