@gamaze/hicortex 0.13.2 → 0.13.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/dist/consolidate.d.ts +1 -1
- package/dist/consolidate.js +1 -1
- package/dist/context-cli.js +1 -1
- package/dist/domain-classify.d.ts +3 -3
- package/dist/domain-classify.js +3 -3
- package/dist/hermes-transcript-reader.d.ts +1 -1
- package/dist/hermes-transcript-reader.js +1 -1
- package/dist/lessons-context.d.ts +1 -1
- package/dist/lessons-context.js +2 -2
- package/dist/pi-transcript-reader.d.ts +3 -3
- package/dist/pi-transcript-reader.js +5 -5
- package/dist/transcript-reader.d.ts +1 -1
- package/dist/transcript-reader.js +2 -2
- package/domains.example.json +53 -13
- package/hermes-plugin/hicortex/provider.py +4 -4
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/dist/consolidate.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ import { type DomainDef } from "./domain-classify.js";
|
|
|
12
12
|
* Minimum COSINE similarity for a link candidate.
|
|
13
13
|
*
|
|
14
14
|
* Calibration (2026-07): measured top-10 neighbor cosine histogram on the
|
|
15
|
-
*
|
|
15
|
+
* ~3000-memory production corpus. Typical top-1 neighbor cosine:
|
|
16
16
|
* median 0.823, p10 0.743, p90 0.902. Threshold 0.75 combined with the
|
|
17
17
|
* top-3 cap yields ≈ 2.2 candidate links/memory. The previous value (0.55)
|
|
18
18
|
* lived on an accidental 1−L2 scale where it required cosine > 0.90 — a
|
package/dist/consolidate.js
CHANGED
|
@@ -65,7 +65,7 @@ const CONSOLIDATE_PRUNE_MIN_AGE_DAYS = 90;
|
|
|
65
65
|
* Minimum COSINE similarity for a link candidate.
|
|
66
66
|
*
|
|
67
67
|
* Calibration (2026-07): measured top-10 neighbor cosine histogram on the
|
|
68
|
-
*
|
|
68
|
+
* ~3000-memory production corpus. Typical top-1 neighbor cosine:
|
|
69
69
|
* median 0.823, p10 0.743, p90 0.902. Threshold 0.75 combined with the
|
|
70
70
|
* top-3 cap yields ≈ 2.2 candidate links/memory. The previous value (0.55)
|
|
71
71
|
* lived on an accidental 1−L2 scale where it required cosine > 0.90 — a
|
package/dist/context-cli.js
CHANGED
|
@@ -261,7 +261,7 @@ function extractAgentFlag(args) {
|
|
|
261
261
|
// A missing value (end of args) or the next token being another flag is a
|
|
262
262
|
// typo — never let it silently fall through to the global scope.
|
|
263
263
|
if (val === undefined || val.startsWith("-")) {
|
|
264
|
-
throw new ContextCliError("--agent requires a value, e.g. --agent
|
|
264
|
+
throw new ContextCliError("--agent requires a value, e.g. --agent alice");
|
|
265
265
|
}
|
|
266
266
|
agent = val;
|
|
267
267
|
i++;
|
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
* ---------------
|
|
6
6
|
* The nightly's legacy `stageDomainCuration` groups PROJECTS into domains and
|
|
7
7
|
* assigns every memory its project's domain. For an owner whose "projects" are
|
|
8
|
-
* often AGENT names (
|
|
8
|
+
* often AGENT names (alice, bob, ...), one agent produces memories spanning
|
|
9
9
|
* many life areas, so life-memories get smeared under the agent. This module
|
|
10
10
|
* classifies a single memory into life-spheres by its CONTENT, drawn from a
|
|
11
11
|
* user-curated vocabulary in ~/.hicortex/config.json (`domains`).
|
|
12
12
|
*
|
|
13
13
|
* GRADED SCHEMA TAGS (spec 2026-07-07, supersedes the LLM-picked primary from
|
|
14
|
-
* PR #152/#153): a memory genuinely spans spheres — "set up
|
|
14
|
+
* PR #152/#153): a memory genuinely spans spheres — "set up the server for the
|
|
15
15
|
* agent fleet" is both Hardware AND Ventures. The classifier now returns ONLY
|
|
16
16
|
* the discrete part:
|
|
17
17
|
* - `tags`: 0..N vocabulary names that genuinely apply, MOST-RELEVANT FIRST
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
*
|
|
32
32
|
* The `project` name is passed to the classifier as a HINT (content wins;
|
|
33
33
|
* project only breaks ties). This rescues terse technical memories from
|
|
34
|
-
* projects
|
|
34
|
+
* projects whose content alone reads as ambiguous.
|
|
35
35
|
*
|
|
36
36
|
* The classifier makes ONE constrained LLM call per memory (via the classify
|
|
37
37
|
* tier — classifyModel/classifyBaseUrl when configured, else the reflect
|
package/dist/domain-classify.js
CHANGED
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
* ---------------
|
|
7
7
|
* The nightly's legacy `stageDomainCuration` groups PROJECTS into domains and
|
|
8
8
|
* assigns every memory its project's domain. For an owner whose "projects" are
|
|
9
|
-
* often AGENT names (
|
|
9
|
+
* often AGENT names (alice, bob, ...), one agent produces memories spanning
|
|
10
10
|
* many life areas, so life-memories get smeared under the agent. This module
|
|
11
11
|
* classifies a single memory into life-spheres by its CONTENT, drawn from a
|
|
12
12
|
* user-curated vocabulary in ~/.hicortex/config.json (`domains`).
|
|
13
13
|
*
|
|
14
14
|
* GRADED SCHEMA TAGS (spec 2026-07-07, supersedes the LLM-picked primary from
|
|
15
|
-
* PR #152/#153): a memory genuinely spans spheres — "set up
|
|
15
|
+
* PR #152/#153): a memory genuinely spans spheres — "set up the server for the
|
|
16
16
|
* agent fleet" is both Hardware AND Ventures. The classifier now returns ONLY
|
|
17
17
|
* the discrete part:
|
|
18
18
|
* - `tags`: 0..N vocabulary names that genuinely apply, MOST-RELEVANT FIRST
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
*
|
|
33
33
|
* The `project` name is passed to the classifier as a HINT (content wins;
|
|
34
34
|
* project only breaks ties). This rescues terse technical memories from
|
|
35
|
-
* projects
|
|
35
|
+
* projects whose content alone reads as ambiguous.
|
|
36
36
|
*
|
|
37
37
|
* The classifier makes ONE constrained LLM call per memory (via the classify
|
|
38
38
|
* tier — classifyModel/classifyBaseUrl when configured, else the reflect
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Hermes transcript reader — the nightly capture path for Nous Research Hermes.
|
|
3
3
|
*
|
|
4
4
|
* Hermes stores conversation in a SQLite state DB, one per profile:
|
|
5
|
-
* ~/.hermes/profiles/<profile>/state.db (per-profile agents:
|
|
5
|
+
* ~/.hermes/profiles/<profile>/state.db (per-profile agents: alice, bob, carol)
|
|
6
6
|
* ~/.hermes/state.db (global, non-profile setups)
|
|
7
7
|
*
|
|
8
8
|
* Schema (relevant columns):
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Hermes transcript reader — the nightly capture path for Nous Research Hermes.
|
|
4
4
|
*
|
|
5
5
|
* Hermes stores conversation in a SQLite state DB, one per profile:
|
|
6
|
-
* ~/.hermes/profiles/<profile>/state.db (per-profile agents:
|
|
6
|
+
* ~/.hermes/profiles/<profile>/state.db (per-profile agents: alice, bob, carol)
|
|
7
7
|
* ~/.hermes/state.db (global, non-profile setups)
|
|
8
8
|
*
|
|
9
9
|
* Schema (relevant columns):
|
|
@@ -69,7 +69,7 @@ export declare function renderContextBlock(sections: Record<string, string>): st
|
|
|
69
69
|
* into every persona; on a bare fetch (no id) the guard is off (amendment
|
|
70
70
|
* A2).
|
|
71
71
|
* - CC passes `false` ALWAYS and deliberately (see the call site): a thin CC
|
|
72
|
-
* client auto-upgrades via npx BEFORE
|
|
72
|
+
* client auto-upgrades via npx BEFORE the server does, so during the upgrade
|
|
73
73
|
* window it talks to a 0.12 server that cannot hold ANY per-agent config —
|
|
74
74
|
* global IS the operator's intended state there, and a guard would instead
|
|
75
75
|
* blank ALL context for every CC session in that window.
|
package/dist/lessons-context.js
CHANGED
|
@@ -180,7 +180,7 @@ function renderContextBlock(sections) {
|
|
|
180
180
|
* into every persona; on a bare fetch (no id) the guard is off (amendment
|
|
181
181
|
* A2).
|
|
182
182
|
* - CC passes `false` ALWAYS and deliberately (see the call site): a thin CC
|
|
183
|
-
* client auto-upgrades via npx BEFORE
|
|
183
|
+
* client auto-upgrades via npx BEFORE the server does, so during the upgrade
|
|
184
184
|
* window it talks to a 0.12 server that cannot hold ANY per-agent config —
|
|
185
185
|
* global IS the operator's intended state there, and a guard would instead
|
|
186
186
|
* blank ALL context for every CC session in that window.
|
|
@@ -216,7 +216,7 @@ async function fetchContextBlock(cfg) {
|
|
|
216
216
|
return null;
|
|
217
217
|
const data = await resp.json();
|
|
218
218
|
// CC deliberately passes requireAgentEcho: false (NOT the OC/Hermes old-server
|
|
219
|
-
// guard). A thin CC client auto-upgrades via npx BEFORE
|
|
219
|
+
// guard). A thin CC client auto-upgrades via npx BEFORE the server does, so
|
|
220
220
|
// mid-upgrade it may hit a 0.12 server that returns global context with no
|
|
221
221
|
// `agent` echo — and a 0.12 server cannot hold per-agent config, so global is
|
|
222
222
|
// the intended state. Guarding here would blank ALL CC context in that window.
|
|
@@ -16,14 +16,14 @@
|
|
|
16
16
|
*
|
|
17
17
|
* Directory layout:
|
|
18
18
|
* ~/.pi/agent/sessions/
|
|
19
|
-
* --home-
|
|
19
|
+
* --home-alice-projects-myagent--/
|
|
20
20
|
* 2026-04-10T18-37-44-615Z_<uuid>.jsonl
|
|
21
21
|
* 2026-04-11T07-51-28-282Z_<uuid>.jsonl
|
|
22
22
|
* --home-agents-Development-MAIC--/
|
|
23
23
|
* ...
|
|
24
24
|
*
|
|
25
|
-
* The encoded-cwd uses double-dash separators: /home/
|
|
26
|
-
* becomes --home-
|
|
25
|
+
* The encoded-cwd uses double-dash separators: /home/alice/projects/myagent
|
|
26
|
+
* becomes --home-alice-projects-myagent--. The session header's `cwd` field
|
|
27
27
|
* is the canonical path; the directory name is a filesystem-safe encoding.
|
|
28
28
|
*/
|
|
29
29
|
import type { TranscriptBatch, CursorMap } from "./transcript-reader.js";
|
|
@@ -17,14 +17,14 @@
|
|
|
17
17
|
*
|
|
18
18
|
* Directory layout:
|
|
19
19
|
* ~/.pi/agent/sessions/
|
|
20
|
-
* --home-
|
|
20
|
+
* --home-alice-projects-myagent--/
|
|
21
21
|
* 2026-04-10T18-37-44-615Z_<uuid>.jsonl
|
|
22
22
|
* 2026-04-11T07-51-28-282Z_<uuid>.jsonl
|
|
23
23
|
* --home-agents-Development-MAIC--/
|
|
24
24
|
* ...
|
|
25
25
|
*
|
|
26
|
-
* The encoded-cwd uses double-dash separators: /home/
|
|
27
|
-
* becomes --home-
|
|
26
|
+
* The encoded-cwd uses double-dash separators: /home/alice/projects/myagent
|
|
27
|
+
* becomes --home-alice-projects-myagent--. The session header's `cwd` field
|
|
28
28
|
* is the canonical path; the directory name is a filesystem-safe encoding.
|
|
29
29
|
*/
|
|
30
30
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -157,7 +157,7 @@ function readPiTranscripts(since, sessionsDir = DEFAULT_PI_SESSIONS_DIR, cursors
|
|
|
157
157
|
}
|
|
158
158
|
/**
|
|
159
159
|
* Extract the last path segment from a cwd as the project name.
|
|
160
|
-
* /home/
|
|
160
|
+
* /home/alice/projects/myagent → "myagent"
|
|
161
161
|
* Falls back to decoding the directory name if cwd is empty.
|
|
162
162
|
*/
|
|
163
163
|
function deriveProjectName(cwd, encodedDir) {
|
|
@@ -165,7 +165,7 @@ function deriveProjectName(cwd, encodedDir) {
|
|
|
165
165
|
const segments = cwd.split("/").filter(Boolean);
|
|
166
166
|
return segments[segments.length - 1] ?? "unknown";
|
|
167
167
|
}
|
|
168
|
-
// Decode the Pi directory encoding: --home-
|
|
168
|
+
// Decode the Pi directory encoding: --home-alice-projects-myagent-- → myagent
|
|
169
169
|
const decoded = encodedDir.replace(/^--/, "").replace(/--$/, "").split("-");
|
|
170
170
|
return decoded[decoded.length - 1] ?? "unknown";
|
|
171
171
|
}
|
|
@@ -15,7 +15,7 @@ export interface TranscriptBatch {
|
|
|
15
15
|
date: string;
|
|
16
16
|
entries: unknown[];
|
|
17
17
|
/**
|
|
18
|
-
* Optional source-agent label (e.g. "hermes/
|
|
18
|
+
* Optional source-agent label (e.g. "hermes/alice"). When set, the nightly
|
|
19
19
|
* pipeline uses it verbatim for provenance instead of the default
|
|
20
20
|
* `claude-code/<project>`. Lets per-harness readers stamp their own origin.
|
|
21
21
|
*/
|
|
@@ -159,12 +159,12 @@ function parseTranscriptFile(filePath, projectName, cursorKey, startCursor, gene
|
|
|
159
159
|
}
|
|
160
160
|
/**
|
|
161
161
|
* Decode CC project directory name to a human-readable project name.
|
|
162
|
-
* CC uses path-based hashing: "-Users-
|
|
162
|
+
* CC uses path-based hashing: "-Users-alice-Development-Tools-hicortex"
|
|
163
163
|
* becomes "hicortex" (last path component).
|
|
164
164
|
*/
|
|
165
165
|
function decodeProjectDirName(dirName) {
|
|
166
166
|
// CC encodes paths by replacing / with -
|
|
167
|
-
// e.g. "-Users-
|
|
167
|
+
// e.g. "-Users-alice-Development-Tools-hicortex"
|
|
168
168
|
const parts = dirName.split("-").filter(Boolean);
|
|
169
169
|
if (parts.length === 0)
|
|
170
170
|
return dirName;
|
package/domains.example.json
CHANGED
|
@@ -9,11 +9,26 @@
|
|
|
9
9
|
"Backfill an existing corpus with: hicortex classify-domains"
|
|
10
10
|
],
|
|
11
11
|
"domains": [
|
|
12
|
-
{
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
{
|
|
12
|
+
{
|
|
13
|
+
"name": "Work",
|
|
14
|
+
"description": "Your job and professional life — employer, clients, workstreams"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"name": "Personal",
|
|
18
|
+
"description": "Private life — home, hobbies, everyday matters"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "People",
|
|
22
|
+
"description": "Relationships — family, friends, social life, network"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"name": "Health",
|
|
26
|
+
"description": "Fitness, wellbeing, medical"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"name": "Finance",
|
|
30
|
+
"description": "Money — budgeting, spending, investing"
|
|
31
|
+
}
|
|
17
32
|
],
|
|
18
33
|
"_powerUserExample": {
|
|
19
34
|
"_readme": [
|
|
@@ -22,14 +37,39 @@
|
|
|
22
37
|
"`weakPrimaryFloor` (default 0.45) is the minimum embedding similarity for a no-fit memory to earn a weak primary; tune it from your corpus."
|
|
23
38
|
],
|
|
24
39
|
"domains": [
|
|
25
|
-
{
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
{
|
|
31
|
-
|
|
32
|
-
|
|
40
|
+
{
|
|
41
|
+
"name": "Work",
|
|
42
|
+
"description": "Employer, day job, client projects, workstreams",
|
|
43
|
+
"compartment": true
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"name": "Personal",
|
|
47
|
+
"description": "Private life — home, hobbies, everyday matters"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"name": "People",
|
|
51
|
+
"description": "Relationships — family, friends, social life, network"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"name": "Health",
|
|
55
|
+
"description": "Fitness, wellbeing, medical"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"name": "Finance",
|
|
59
|
+
"description": "Money — budgeting, spending, investing"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"name": "Photography",
|
|
63
|
+
"description": "Camera gear, shoots, editing workflow, photo projects"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"name": "Home",
|
|
67
|
+
"description": "House, renovation projects, maintenance, garden"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"name": "Travel",
|
|
71
|
+
"description": "Trips, destinations, bookings, travel plans"
|
|
72
|
+
}
|
|
33
73
|
],
|
|
34
74
|
"weakPrimaryFloor": 0.5
|
|
35
75
|
}
|
|
@@ -33,8 +33,8 @@ _INJECT_CONTENT_CAP = 500
|
|
|
33
33
|
|
|
34
34
|
# Agent ids are joined into a filesystem path server-side, so they share the
|
|
35
35
|
# section-name allowlist. \Z (NOT $) anchors the END OF STRING: Python's $ also
|
|
36
|
-
# matches just before a trailing "\n", so "
|
|
37
|
-
# agent=
|
|
36
|
+
# matches just before a trailing "\n", so "alice\n" would pass and go out as
|
|
37
|
+
# agent=alice%0A → a 400 the fail-soft path silently swallows.
|
|
38
38
|
_AGENT_ID_RE = re.compile(r"^[a-z0-9][a-z0-9_-]*\Z")
|
|
39
39
|
|
|
40
40
|
|
|
@@ -48,7 +48,7 @@ def _sanitize_agent_id(raw: Optional[str]) -> Optional[str]:
|
|
|
48
48
|
EXACTLY so a profile resolves to the SAME id on both harnesses (a mismatch
|
|
49
49
|
would make one honor the persona firewall and the other leak global context
|
|
50
50
|
into an ``off``/``override`` persona): lowercase → collapse invalid runs to
|
|
51
|
-
"-" → strip leading -/_ → truncate 64 → validate. "
|
|
51
|
+
"-" → strip leading -/_ → truncate 64 → validate. "Alice" → "alice";
|
|
52
52
|
"MacBook-Pro.local" → "macbook-pro-local"; all-symbols → None."""
|
|
53
53
|
if not isinstance(raw, str):
|
|
54
54
|
return None
|
|
@@ -73,7 +73,7 @@ def _resolve_agent_name(cfg: Dict[str, Any]) -> Optional[str]:
|
|
|
73
73
|
2. ``HERMES_PROFILE`` env;
|
|
74
74
|
3. parse ``HERMES_HOME`` when it ends ``profiles/<name>``;
|
|
75
75
|
4. None → bare fetch → the global set.
|
|
76
|
-
Each source is stripped then SANITIZED (not rejected) so "
|
|
76
|
+
Each source is stripped then SANITIZED (not rejected) so "Alice" → "alice"
|
|
77
77
|
matches the TS contract; a source that sanitizes to None yields None (bare
|
|
78
78
|
fetch), never a fall-through to another identity."""
|
|
79
79
|
configured = (cfg.get("agent_name") or "").strip()
|
package/openclaw.plugin.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"serverUrl": {
|
|
12
12
|
"type": "string",
|
|
13
13
|
"default": "http://127.0.0.1:8787",
|
|
14
|
-
"description": "Hicortex server URL. Defaults to localhost (co-located server). For multi-machine setups, point this at the remote server (e.g. http://
|
|
14
|
+
"description": "Hicortex server URL. Defaults to localhost (co-located server). For multi-machine setups, point this at the remote server (e.g. http://your-server:8787 or an HTTPS URL)."
|
|
15
15
|
},
|
|
16
16
|
"authToken": {
|
|
17
17
|
"type": "string",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gamaze/hicortex",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.3",
|
|
4
4
|
"description": "Self-learning memory for AI agents \u2014 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": {
|