@gamaze/hicortex 0.16.1 → 0.16.2
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 -0
- package/dist/capture.d.ts +18 -1
- package/dist/capture.js +3 -2
- package/dist/classify-domains.d.ts +1 -1
- package/dist/classify-domains.js +5 -7
- package/dist/cli.js +10 -2
- package/dist/cluster.d.ts +5 -4
- package/dist/cluster.js +2 -3
- package/dist/consolidate.js +2 -4
- package/dist/db.js +23 -0
- package/dist/dedup.js +1 -1
- package/dist/distiller.js +2 -2
- package/dist/domain-classify.d.ts +1 -1
- package/dist/domain-classify.js +1 -5
- package/dist/eval/run-eval.js +0 -1
- package/dist/index.js +0 -1
- package/dist/init.d.ts +165 -0
- package/dist/init.js +283 -57
- package/dist/mcp-server.js +71 -25
- package/dist/nightly.js +35 -3
- package/dist/nofit.d.ts +1 -1
- package/dist/nofit.js +1 -2
- package/dist/prompts.js +0 -7
- package/dist/recall-index.d.ts +13 -17
- package/dist/recall-index.js +11 -21
- package/dist/retrieval.d.ts +7 -7
- package/dist/retrieval.js +20 -24
- package/dist/schema-prototypes.d.ts +8 -13
- package/dist/schema-prototypes.js +13 -22
- package/dist/seed-lesson.js +0 -1
- package/dist/storage.d.ts +9 -12
- package/dist/storage.js +19 -21
- package/dist/types.d.ts +47 -23
- package/domains.example.json +2 -3
- package/hermes-plugin/hicortex/README.md +3 -1
- package/hermes-plugin/hicortex/config.py +33 -2
- package/hermes-plugin/hicortex/plugin.yaml +1 -1
- package/hermes-plugin/hicortex/provider.py +5 -0
- package/package.json +1 -1
package/dist/storage.js
CHANGED
|
@@ -69,10 +69,10 @@ function insertMemory(db, content, embedding, opts = {}) {
|
|
|
69
69
|
const result = db
|
|
70
70
|
.prepare(`INSERT OR IGNORE INTO memories
|
|
71
71
|
(id, content, base_strength, last_accessed, access_count,
|
|
72
|
-
created_at, ingested_at, source_agent,
|
|
73
|
-
privacy, memory_type)
|
|
74
|
-
VALUES (?, ?, ?, ?, 0, ?, ?, ?, ?, ?, ?, ?)`)
|
|
75
|
-
.run(id, content, opts.baseStrength ?? 0.5, ts, ts, ingestedTs, opts.sourceAgent ?? "default", sourceSession, opts.project ?? null, opts.privacy ??
|
|
72
|
+
created_at, ingested_at, source_agent, source_agent_id, source_session,
|
|
73
|
+
source_domain, project, privacy, memory_type)
|
|
74
|
+
VALUES (?, ?, ?, ?, 0, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
75
|
+
.run(id, content, opts.baseStrength ?? 0.5, ts, ts, ingestedTs, opts.sourceAgent ?? "default", opts.sourceAgentId ?? null, sourceSession, opts.sourceDomain ?? null, opts.project ?? null, opts.privacy ?? null, opts.memoryType ?? "episode");
|
|
76
76
|
if (result.changes > 0) {
|
|
77
77
|
// New row — store its vector.
|
|
78
78
|
db.prepare("INSERT INTO memory_vectors (id, embedding) VALUES (?, ?)").run(id, embedToBlob(embedding));
|
|
@@ -192,9 +192,8 @@ function deleteMemory(db, memoryId) {
|
|
|
192
192
|
* row stores its association weight (NULL when not yet computed).
|
|
193
193
|
*
|
|
194
194
|
* The PRIMARY (memories.domain) is DERIVED here — never passed in by the LLM:
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
* weights never diverge.
|
|
195
|
+
* argmax weight, else first tag (all-null weights). The whole update is one
|
|
196
|
+
* transaction so domain, tag set, and weights never diverge.
|
|
198
197
|
*
|
|
199
198
|
* @returns the derived primary written to memories.domain
|
|
200
199
|
*/
|
|
@@ -209,7 +208,7 @@ function setMemoryTags(db, memoryId, tags, options = {}) {
|
|
|
209
208
|
tag,
|
|
210
209
|
weight: options.weights?.[tag] ?? null,
|
|
211
210
|
}));
|
|
212
|
-
const primary = (0, schema_prototypes_js_1.derivePrimary)(weighted
|
|
211
|
+
const primary = (0, schema_prototypes_js_1.derivePrimary)(weighted);
|
|
213
212
|
const setDomain = db.prepare("UPDATE memories SET domain = ? WHERE id = ?");
|
|
214
213
|
const clearTags = db.prepare("DELETE FROM memory_tags WHERE memory_id = ?");
|
|
215
214
|
const insertTag = db.prepare("INSERT OR IGNORE INTO memory_tags (memory_id, tag, weight) VALUES (?, ?, ?)");
|
|
@@ -352,9 +351,10 @@ function getBm25Weights() {
|
|
|
352
351
|
*
|
|
353
352
|
* `project` is NOT a filter here (#203): the hard project WHERE from #192 was
|
|
354
353
|
* removed — project is now a soft affinity boost in retrieval.computeScore AND
|
|
355
|
-
* a weighted field in BM25F (#205). `privacy`
|
|
356
|
-
*
|
|
357
|
-
*
|
|
354
|
+
* a weighted field in BM25F (#205). `privacy` is NOT a filter (0.16.x: the
|
|
355
|
+
* column is fully vestigial — stored, never filtered; the privacy IN-clause
|
|
356
|
+
* was removed). `sourceAgent` stays a hard filter (kept for completeness; no
|
|
357
|
+
* production caller of retrieve() currently passes it).
|
|
358
358
|
*
|
|
359
359
|
* #205 sign handling: FTS5's `bm25(table, w0, w1, …)` returns a NEGATIVE score
|
|
360
360
|
* where MORE-negative = better match (it is 1 − the normalized BM25 score,
|
|
@@ -365,14 +365,9 @@ function getBm25Weights() {
|
|
|
365
365
|
* positionally as parameters (NOT string-interpolated) so query-planner
|
|
366
366
|
* caching is unaffected and the config path is the only editor.
|
|
367
367
|
*/
|
|
368
|
-
function searchFts(db, query, limit = 10,
|
|
368
|
+
function searchFts(db, query, limit = 10, sourceAgent) {
|
|
369
369
|
const conditions = ["memories_fts MATCH ?"];
|
|
370
370
|
const params = [query];
|
|
371
|
-
if (privacy && privacy.length > 0) {
|
|
372
|
-
const placeholders = privacy.map(() => "?").join(", ");
|
|
373
|
-
conditions.push(`m.privacy IN (${placeholders})`);
|
|
374
|
-
params.push(...privacy);
|
|
375
|
-
}
|
|
376
371
|
if (sourceAgent) {
|
|
377
372
|
conditions.push("m.source_agent = ?");
|
|
378
373
|
params.push(sourceAgent);
|
|
@@ -460,18 +455,21 @@ function deleteLinks(db, memoryId) {
|
|
|
460
455
|
* Batch insert memories. Returns count inserted.
|
|
461
456
|
*/
|
|
462
457
|
function insertMemoriesBatch(db, memories) {
|
|
458
|
+
// privacy default is null (0.16.x: the distiller no longer sets WORK — the
|
|
459
|
+
// column is vestigial, never filtered, and goes NULL unless a caller sends
|
|
460
|
+
// an explicit value).
|
|
463
461
|
const insertMem = db.prepare(`INSERT INTO memories
|
|
464
462
|
(id, content, base_strength, last_accessed, access_count,
|
|
465
|
-
created_at, ingested_at, source_agent,
|
|
466
|
-
privacy, memory_type)
|
|
467
|
-
VALUES (?, ?, ?, ?, 0, ?, ?, ?, ?, ?, ?, ?)`);
|
|
463
|
+
created_at, ingested_at, source_agent, source_agent_id, source_session,
|
|
464
|
+
source_domain, project, privacy, memory_type)
|
|
465
|
+
VALUES (?, ?, ?, ?, 0, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
468
466
|
const insertVec = db.prepare("INSERT INTO memory_vectors (id, embedding) VALUES (?, ?)");
|
|
469
467
|
const tx = db.transaction(() => {
|
|
470
468
|
let count = 0;
|
|
471
469
|
for (const mem of memories) {
|
|
472
470
|
const id = (0, node_crypto_1.randomUUID)();
|
|
473
471
|
const ts = nowIso();
|
|
474
|
-
insertMem.run(id, mem.content, mem.baseStrength ?? 0.5, ts, ts, ts, mem.sourceAgent ?? "default", mem.sourceSession ?? null, mem.project ?? null, mem.privacy ??
|
|
472
|
+
insertMem.run(id, mem.content, mem.baseStrength ?? 0.5, ts, ts, ts, mem.sourceAgent ?? "default", mem.sourceAgentId ?? null, mem.sourceSession ?? null, mem.sourceDomain ?? null, mem.project ?? null, mem.privacy ?? null, mem.memoryType ?? "episode");
|
|
475
473
|
insertVec.run(id, embedToBlob(mem.embedding));
|
|
476
474
|
count++;
|
|
477
475
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -13,9 +13,23 @@ export interface Memory {
|
|
|
13
13
|
ingested_at: string;
|
|
14
14
|
source_agent: string;
|
|
15
15
|
source_session: string | null;
|
|
16
|
+
/**
|
|
17
|
+
* Stable attribution id of the capturing client (a per-install UUID from
|
|
18
|
+
* config.json `agentId`). Survives agent/machine renames — unlike
|
|
19
|
+
* `source_agent` (a readable name). Attribution only; nothing filters on it.
|
|
20
|
+
* NULL on memories captured before this column existed. (0.16.x)
|
|
21
|
+
*/
|
|
22
|
+
source_agent_id: string | null;
|
|
16
23
|
project: string | null;
|
|
17
24
|
domain: string | null;
|
|
18
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Provenance only (0.16.x): the client-declared topic/domain of the
|
|
27
|
+
* capturing agent (config.json `sourceDomain`). NOT used for recall filtering
|
|
28
|
+
* or scoring, and NOT the content-classified primary (that is `domain`
|
|
29
|
+
* above). NULL when the client declares none. Echoed back on /memory GET.
|
|
30
|
+
*/
|
|
31
|
+
source_domain: string | null;
|
|
32
|
+
privacy: ("PUBLIC" | "WORK" | "PERSONAL" | "SENSITIVE") | null;
|
|
19
33
|
memory_type: "episode" | "lesson" | "fact" | "decision";
|
|
20
34
|
updated_at: string | null;
|
|
21
35
|
}
|
|
@@ -157,6 +171,15 @@ export interface HicortexConfig {
|
|
|
157
171
|
serverUrl?: string;
|
|
158
172
|
/** Bearer token for the Hicortex server. Localhost bypasses auth by default. */
|
|
159
173
|
authToken?: string;
|
|
174
|
+
/**
|
|
175
|
+
* Stable per-install UUID generated by `init` (see ensureAgentId in init.ts;
|
|
176
|
+
* never rotated). Attribution identity of the capturing client — stored on
|
|
177
|
+
* each captured memory as `source_agent_id` (see Memory.source_agent_id) and
|
|
178
|
+
* sent on every /distill segment. Survives agent/machine renames, unlike the
|
|
179
|
+
* readable `source_agent` name. Pure attribution; nothing filters or scopes
|
|
180
|
+
* on it. (0.16.x)
|
|
181
|
+
*/
|
|
182
|
+
agentId?: string;
|
|
160
183
|
/** @deprecated Use the Hicortex server for distillation and consolidation. */
|
|
161
184
|
llmBaseUrl?: string;
|
|
162
185
|
/** @deprecated Use the Hicortex server for distillation and consolidation. */
|
|
@@ -194,6 +217,21 @@ export interface HicortexConfig {
|
|
|
194
217
|
consolidateHour?: number;
|
|
195
218
|
/** @deprecated The OC plugin no longer opens its own database. */
|
|
196
219
|
dbPath?: string;
|
|
220
|
+
/**
|
|
221
|
+
* Client-declared topic/domain of THIS capturing agent (provenance only,
|
|
222
|
+
* 0.16.x). Sent on captured memories as `source_domain` (see
|
|
223
|
+
* Memory.source_domain) — NOT used for recall filtering or scoring, and NOT
|
|
224
|
+
* the content-classified primary (which is the server-derived `domain`
|
|
225
|
+
* column on each memory, classified against `domains` below).
|
|
226
|
+
*
|
|
227
|
+
* DISTINCT from `domains` (plural) directly below: `domains` is the
|
|
228
|
+
* config-owned VOCABULARY — the server's life-sphere list that memories are
|
|
229
|
+
* content-classified against; this singular `sourceDomain` is the client
|
|
230
|
+
* declaring "I am an agent that works on topic X", recorded as provenance on
|
|
231
|
+
* what it captures. Do not conflate the two. (Renamed from `domain` in
|
|
232
|
+
* 0.16.x — one char from `domains`, meant something unrelated.)
|
|
233
|
+
*/
|
|
234
|
+
sourceDomain?: string;
|
|
197
235
|
/**
|
|
198
236
|
* Optional config-owned domain list — the user's top-level memory spheres
|
|
199
237
|
* (life areas OR project/topic areas). When present, the nightly multi-tag
|
|
@@ -205,7 +243,7 @@ export interface HicortexConfig {
|
|
|
205
243
|
* Server-mode `init` scaffolds a generic 5-domain default (Work, Personal,
|
|
206
244
|
* People, Health, Finance — see GENERIC_DEFAULT_DOMAINS in init.ts) when
|
|
207
245
|
* this key is absent, and NEVER touches an existing list. A power-user
|
|
208
|
-
* example (
|
|
246
|
+
* example (custom weakPrimaryFloor) ships as
|
|
209
247
|
* domains.example.json in the package root.
|
|
210
248
|
*
|
|
211
249
|
* NO fallback bucket is needed or special-cased (owner amendment 07.07):
|
|
@@ -227,13 +265,6 @@ export interface HicortexConfig {
|
|
|
227
265
|
export interface DomainDef {
|
|
228
266
|
name: string;
|
|
229
267
|
description: string;
|
|
230
|
-
/**
|
|
231
|
-
* Deliberate compartmentalization (graded-schema spec, 07.07.2026): when
|
|
232
|
-
* true, this domain becomes the PRIMARY (memories.domain) whenever it is
|
|
233
|
-
* tagged, overriding the argmax-weight rule. The owner's config flags only
|
|
234
|
-
* Work — a work/life firewall. Optional; absent = false.
|
|
235
|
-
*/
|
|
236
|
-
compartment?: boolean;
|
|
237
268
|
}
|
|
238
269
|
/** Response from license validation API. */
|
|
239
270
|
export interface LicenseInfo {
|
|
@@ -286,8 +317,14 @@ export interface ModuleIndex {
|
|
|
286
317
|
export interface InsertMemoryOptions {
|
|
287
318
|
sourceAgent?: string;
|
|
288
319
|
sourceSession?: string | null;
|
|
320
|
+
/** Stable client UUID (config.json `agentId`). Attribution only. */
|
|
321
|
+
sourceAgentId?: string | null;
|
|
322
|
+
/** Client-declared topic/domain of the capturing agent. Provenance only. */
|
|
323
|
+
sourceDomain?: string | null;
|
|
289
324
|
project?: string | null;
|
|
290
|
-
|
|
325
|
+
/** 0.16.x: vestigial — stored but never filtered. null (or absent) when the
|
|
326
|
+
* caller doesn't declare one; an explicit value is honored as-is. */
|
|
327
|
+
privacy?: string | null;
|
|
291
328
|
memoryType?: string;
|
|
292
329
|
baseStrength?: number;
|
|
293
330
|
createdAt?: string;
|
|
@@ -297,16 +334,3 @@ export interface VectorSearchOptions {
|
|
|
297
334
|
limit?: number;
|
|
298
335
|
excludeIds?: string[];
|
|
299
336
|
}
|
|
300
|
-
/** Options for FTS search. */
|
|
301
|
-
export interface FtsSearchOptions {
|
|
302
|
-
limit?: number;
|
|
303
|
-
privacy?: string[];
|
|
304
|
-
sourceAgent?: string;
|
|
305
|
-
}
|
|
306
|
-
/** Options for retrieval. */
|
|
307
|
-
export interface RetrievalOptions {
|
|
308
|
-
limit?: number;
|
|
309
|
-
project?: string | null;
|
|
310
|
-
privacy?: string[];
|
|
311
|
-
sourceAgent?: string;
|
|
312
|
-
}
|
package/domains.example.json
CHANGED
|
@@ -33,14 +33,13 @@
|
|
|
33
33
|
"_powerUserExample": {
|
|
34
34
|
"_readme": [
|
|
35
35
|
"A narrower life-sphere set for users who want tighter buckets.",
|
|
36
|
-
"
|
|
36
|
+
"The PRIMARY domain is derived by argmax association weight (LLM tag order breaks ties) — no manual override flag.",
|
|
37
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."
|
|
38
38
|
],
|
|
39
39
|
"domains": [
|
|
40
40
|
{
|
|
41
41
|
"name": "Work",
|
|
42
|
-
"description": "Employer, day job, client projects, workstreams"
|
|
43
|
-
"compartment": true
|
|
42
|
+
"description": "Employer, day job, client projects, workstreams"
|
|
44
43
|
},
|
|
45
44
|
{
|
|
46
45
|
"name": "Personal",
|
|
@@ -22,7 +22,7 @@ That's the whole surface. No `sync_turn`, no compaction/session-end capture —
|
|
|
22
22
|
|
|
23
23
|
### Pushed recall index (0.7.0, server ≥ 0.14)
|
|
24
24
|
|
|
25
|
-
Instead of injecting full memory content every turn, `prefetch` sends the user's message to the server's `POST /recall-index` and injects the returned **index block** verbatim — one line per memory (id, title, date), capped and relevance-gated server-side. The agent fetches full content with `hicortex_get(id)` only when a line is actually relevant; that fetch is what strengthens the memory (exposure ≠ use). All tuning knobs (`recallMaxItems`, `recallMinSimilarity`, `recallReshowTurns`, `recallMinPromptChars`, …) live in the **server** config — the plugin carries none. Dedup is turn-based and server-side per session; the plugin resets it at `initialize` (the Hermes `MemoryProvider` interface exposes no compaction signal, so a mid-session context rebuild cannot trigger a reset — the server's turn-based re-show window covers that gap). Against a pre-0.14 server (404) the plugin falls back to the 0.6.x `GET /search` full-content prefetch, fail-soft, re-probing the endpoint every 10 minutes so a later server upgrade is picked up without a gateway restart. The recall calls carry the profile's configured `
|
|
25
|
+
Instead of injecting full memory content every turn, `prefetch` sends the user's message to the server's `POST /recall-index` and injects the returned **index block** verbatim — one line per memory (id, title, date), capped and relevance-gated server-side. The agent fetches full content with `hicortex_get(id)` only when a line is actually relevant; that fetch is what strengthens the memory (exposure ≠ use). All tuning knobs (`recallMaxItems`, `recallMinSimilarity`, `recallReshowTurns`, `recallMinPromptChars`, …) live in the **server** config — the plugin carries none. Dedup is turn-based and server-side per session; the plugin resets it at `initialize` (the Hermes `MemoryProvider` interface exposes no compaction signal, so a mid-session context rebuild cannot trigger a reset — the server's turn-based re-show window covers that gap). Against a pre-0.14 server (404) the plugin falls back to the 0.6.x `GET /search` full-content prefetch, fail-soft, re-probing the endpoint every 10 minutes so a later server upgrade is picked up without a gateway restart. The recall calls carry the profile's configured `default_project` (and `mission_domains`) and use a short dedicated timeout (1.5 s) so a slow server can never stall a turn. (`privacy_filter` is deprecated since 0.7.2 — the server ignores privacy; see [Configuration](#configuration).)
|
|
26
26
|
|
|
27
27
|
### Per-agent standing context (0.13)
|
|
28
28
|
|
|
@@ -84,6 +84,8 @@ export HICORTEX_AUTH_TOKEN=hctx-default-token # or your custom token
|
|
|
84
84
|
|
|
85
85
|
Env overrides: `HICORTEX_URL`, `HICORTEX_AUTH_TOKEN`.
|
|
86
86
|
|
|
87
|
+
> **`privacy_filter` is DEPRECATED** (plugin 0.7.2 / server 0.16.2). The server no longer filters on privacy — the `privacy` column is vestigial (stored, never filtered). The setting is still accepted for backward compatibility but is now a harmless no-op; setting it emits a one-time-per-process warning in the gateway log. For work/personal isolation, run a **separate Hicortex server** per scope rather than relying on in-server privacy filtering.
|
|
88
|
+
|
|
87
89
|
## Topology
|
|
88
90
|
|
|
89
91
|
- **Server host:** runs Hicortex. Set `hicortex_url: http://localhost:8787` (localhost bypasses auth).
|
|
@@ -8,9 +8,15 @@ plugin also works with env-only setup.
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
10
|
import json
|
|
11
|
+
import logging
|
|
11
12
|
import os
|
|
12
13
|
from typing import Any, Dict, Optional
|
|
13
14
|
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
# One-time-per-process guard for the privacy_filter deprecation warning.
|
|
18
|
+
_privacy_filter_deprecation_warned = False
|
|
19
|
+
|
|
14
20
|
# Declarative config schema — drives `hermes memory setup` (see MemoryProvider
|
|
15
21
|
# .get_config_schema). Field shape per the Hermes MemoryProvider contract:
|
|
16
22
|
# key, label, description, default, required, secret, env_var, choices, url.
|
|
@@ -56,8 +62,15 @@ CONFIG_SCHEMA: list[dict[str, Any]] = [
|
|
|
56
62
|
},
|
|
57
63
|
{
|
|
58
64
|
"key": "privacy_filter",
|
|
59
|
-
"label": "Privacy filter",
|
|
60
|
-
"description":
|
|
65
|
+
"label": "Privacy filter (DEPRECATED)",
|
|
66
|
+
"description": (
|
|
67
|
+
"DEPRECATED since plugin 0.7.2 / server 0.16.2. The server no "
|
|
68
|
+
"longer filters on privacy — the column is vestigial. This setting "
|
|
69
|
+
"is now a harmless no-op: it is still accepted for backward "
|
|
70
|
+
"compat but ignored. For work/personal isolation, run a separate "
|
|
71
|
+
"Hicortex server per scope. (Historically: comma-separated privacy "
|
|
72
|
+
"levels to include, e.g. WORK,PERSONAL.)"
|
|
73
|
+
),
|
|
61
74
|
"default": "WORK,PERSONAL",
|
|
62
75
|
"required": False,
|
|
63
76
|
},
|
|
@@ -94,14 +107,19 @@ def _config_path(hermes_home: Optional[str] = None) -> str:
|
|
|
94
107
|
|
|
95
108
|
def load_config() -> Dict[str, Any]:
|
|
96
109
|
"""Load merged config: file <- env overrides <- defaults."""
|
|
110
|
+
global _privacy_filter_deprecation_warned
|
|
97
111
|
path = _config_path()
|
|
98
112
|
cfg: Dict[str, Any] = {}
|
|
113
|
+
file_set_privacy_filter = False
|
|
99
114
|
if os.path.exists(path):
|
|
100
115
|
try:
|
|
101
116
|
with open(path, encoding="utf-8") as f:
|
|
102
117
|
cfg = json.load(f) or {}
|
|
103
118
|
except Exception:
|
|
104
119
|
cfg = {}
|
|
120
|
+
# Detect an EXPLICIT user setting (the default is applied via setdefault
|
|
121
|
+
# below); only warn when the profile actually configured it.
|
|
122
|
+
file_set_privacy_filter = "privacy_filter" in cfg
|
|
105
123
|
|
|
106
124
|
# Env overrides
|
|
107
125
|
if os.environ.get("HICORTEX_URL"):
|
|
@@ -113,6 +131,19 @@ def load_config() -> Dict[str, Any]:
|
|
|
113
131
|
cfg.setdefault("hicortex_url", "http://localhost:8787")
|
|
114
132
|
cfg.setdefault("recall_limit", 5)
|
|
115
133
|
cfg.setdefault("privacy_filter", "WORK,PERSONAL")
|
|
134
|
+
|
|
135
|
+
# 0.16.2 deprecation: privacy_filter is a no-op now (server ignores privacy
|
|
136
|
+
# entirely). Warn once per process if the profile explicitly sets it.
|
|
137
|
+
if file_set_privacy_filter and not _privacy_filter_deprecation_warned:
|
|
138
|
+
_privacy_filter_deprecation_warned = True
|
|
139
|
+
logger.warning(
|
|
140
|
+
"hicortex: config.json sets 'privacy_filter', which is deprecated "
|
|
141
|
+
"since plugin 0.7.2 / server 0.16.2 — the server no longer filters "
|
|
142
|
+
"on privacy (the column is vestigial). It is a harmless no-op now. "
|
|
143
|
+
"For work/personal isolation, run a separate Hicortex server per "
|
|
144
|
+
"scope. (This warning fires once per process.)"
|
|
145
|
+
)
|
|
146
|
+
|
|
116
147
|
return cfg
|
|
117
148
|
|
|
118
149
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
name: hicortex
|
|
2
|
-
version: 0.7.
|
|
2
|
+
version: 0.7.2
|
|
3
3
|
description: "Self-learning memory for Hermes agents — every session is distilled into lessons overnight, and your agent wakes up wiser. Pushes a compact per-turn recall index (lazy-loaded with hicortex_get), injects fresh lessons plus a per-agent standing context block, and exposes the full 9-tool memory surface (search, get, recent, ingest, lessons, index, graph, update, delete) via a shared Hicortex server. Stdlib-only."
|
|
4
4
|
pip_dependencies: []
|
|
5
5
|
hooks: []
|
|
@@ -446,6 +446,11 @@ class HicortexProvider(MemoryProvider):
|
|
|
446
446
|
lines.append("Lessons:")
|
|
447
447
|
for l in lessons:
|
|
448
448
|
c = (l.get("content") or "").strip().replace("\n", " ")
|
|
449
|
+
# Legacy lessons were stored with a "## Lesson:" prefix; new ones are
|
|
450
|
+
# topic-first (selected by memory_type, not the prefix). Strip it so
|
|
451
|
+
# Hermes renders the same topic-first line as the CC/OC lessons blocks.
|
|
452
|
+
if c.startswith("## Lesson: "):
|
|
453
|
+
c = c[len("## Lesson: "):]
|
|
449
454
|
lines.append(f"- {c[:200]}")
|
|
450
455
|
if idx.get("total"):
|
|
451
456
|
lines.append(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gamaze/hicortex",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.2",
|
|
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": {
|