hippo-memory 1.11.4 → 1.12.0
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/api.d.ts +36 -5
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +161 -70
- package/dist/api.js.map +1 -1
- package/dist/audit.d.ts +1 -1
- package/dist/audit.d.ts.map +1 -1
- package/dist/audit.js.map +1 -1
- package/dist/auth.d.ts +4 -0
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +12 -3
- package/dist/auth.js.map +1 -1
- package/dist/benchmarks/e1.3/incident-recall-eval.js +2 -2
- package/dist/benchmarks/e1.3/incident-recall-eval.js.map +1 -1
- package/dist/benchmarks/e1.3/slack-1000-event-smoke.js +2 -1
- package/dist/benchmarks/e1.3/slack-1000-event-smoke.js.map +1 -1
- package/dist/cli.d.ts +15 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +20 -13
- package/dist/cli.js.map +1 -1
- package/dist/connectors/github/cli-impl.js +3 -2
- package/dist/connectors/github/cli-impl.js.map +1 -1
- package/dist/connectors/github/deletion.js +1 -1
- package/dist/connectors/github/deletion.js.map +1 -1
- package/dist/connectors/github/ingest.d.ts.map +1 -1
- package/dist/connectors/github/ingest.js +2 -1
- package/dist/connectors/github/ingest.js.map +1 -1
- package/dist/connectors/slack/dlq.d.ts +1 -1
- package/dist/connectors/slack/dlq.d.ts.map +1 -1
- package/dist/connectors/slack/dlq.js +2 -1
- package/dist/connectors/slack/dlq.js.map +1 -1
- package/dist/connectors/slack/ingest.d.ts.map +1 -1
- package/dist/connectors/slack/ingest.js +6 -1
- package/dist/connectors/slack/ingest.js.map +1 -1
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +15 -1
- package/dist/db.js.map +1 -1
- package/dist/mcp/server.js +6 -6
- package/dist/mcp/server.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +38 -9
- package/dist/server.js.map +1 -1
- package/dist/src/api.js +161 -70
- package/dist/src/api.js.map +1 -1
- package/dist/src/audit.js.map +1 -1
- package/dist/src/auth.js +12 -3
- package/dist/src/auth.js.map +1 -1
- package/dist/src/cli.js +20 -13
- package/dist/src/cli.js.map +1 -1
- package/dist/src/connectors/github/cli-impl.js +3 -2
- package/dist/src/connectors/github/cli-impl.js.map +1 -1
- package/dist/src/connectors/github/deletion.js +1 -1
- package/dist/src/connectors/github/deletion.js.map +1 -1
- package/dist/src/connectors/github/ingest.js +2 -1
- package/dist/src/connectors/github/ingest.js.map +1 -1
- package/dist/src/connectors/slack/dlq.js +2 -1
- package/dist/src/connectors/slack/dlq.js.map +1 -1
- package/dist/src/connectors/slack/ingest.js +6 -1
- package/dist/src/connectors/slack/ingest.js.map +1 -1
- package/dist/src/db.js +15 -1
- package/dist/src/db.js.map +1 -1
- package/dist/src/mcp/server.js +6 -6
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/server.js +38 -9
- package/dist/src/server.js.map +1 -1
- package/dist/src/version.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
- package/extensions/openclaw-plugin/package.json +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/dist/api.d.ts
CHANGED
|
@@ -13,12 +13,33 @@ import { type MemoryKind, type MemoryEntry } from './memory.js';
|
|
|
13
13
|
import { type AuditEvent, type AuditOp } from './audit.js';
|
|
14
14
|
import { type ApiKeyListItem } from './auth.js';
|
|
15
15
|
import { type AmbientState } from './ambient.js';
|
|
16
|
+
/**
|
|
17
|
+
* Actor identity + authorization role for a Context. v1.12.0 A5 v2 sub-1.
|
|
18
|
+
*
|
|
19
|
+
* Before v1.12.0, Context.actor was a bare string. v1.12.0 promotes it to an
|
|
20
|
+
* object carrying both the audit-log subject (formerly the string itself) and
|
|
21
|
+
* a role for /v1/sleep admin gating. Audit helpers continue accepting `string`
|
|
22
|
+
* — callers pass `ctx.actor.subject`. Role checks happen at the request
|
|
23
|
+
* boundary (e.g. /v1/sleep), not inside api functions.
|
|
24
|
+
*/
|
|
25
|
+
export interface Actor {
|
|
26
|
+
/** 'cli' | 'localhost:cli' | 'api_key:<key_id>' | 'mcp' | 'connector:slack' | 'connector:github' */
|
|
27
|
+
subject: string;
|
|
28
|
+
role: 'admin' | 'member';
|
|
29
|
+
}
|
|
16
30
|
export interface Context {
|
|
17
31
|
hippoRoot: string;
|
|
18
32
|
tenantId: string;
|
|
19
|
-
|
|
20
|
-
actor: string;
|
|
33
|
+
actor: Actor;
|
|
21
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Helper for building process-local (admin-by-default) Actor values. v1.12.0
|
|
37
|
+
* factory used by CLI / MCP / connector Context constructors so the role
|
|
38
|
+
* boilerplate isn't repeated at every site. Bearer-authed callers (HTTP
|
|
39
|
+
* /v1/*) construct Actor directly from the api_keys row's role column via
|
|
40
|
+
* buildContextWithAuth in src/server.ts.
|
|
41
|
+
*/
|
|
42
|
+
export declare function adminActor(subject: string): Actor;
|
|
22
43
|
/**
|
|
23
44
|
* Thrown by `api.recall` when a caller's options violate a recall contract
|
|
24
45
|
* that has been opted into via env. Carries a stable `code` field for HTTP /
|
|
@@ -245,6 +266,16 @@ export interface RecallResult {
|
|
|
245
266
|
* `ctx.tenantId`. The `mode` flag is accepted for forward compatibility (the
|
|
246
267
|
* CLI exposes hybrid/physics paths) but Task 2 wires only the BM25 candidate
|
|
247
268
|
* loader; later tasks can extend this to call the physics/hybrid scorer.
|
|
269
|
+
*
|
|
270
|
+
* **api.recall does NOT mutate `index.last_retrieval_ids`** (v1.11.5 contract
|
|
271
|
+
* lock). The CLI `cmdRecall` (cli.ts) writes `last_retrieval_ids` because the
|
|
272
|
+
* CLI is interactive (user is about to run `hippo outcome --good`). SDK callers
|
|
273
|
+
* are programmatic: they either pass explicit ids to `api.outcome` or call
|
|
274
|
+
* `api.getContext` first for the context-then-outcome workflow (getContext
|
|
275
|
+
* DOES write `last_retrieval_ids`). Adding the side-effect here would change
|
|
276
|
+
* `api.recall` from a pure read into a read+write, breaking SDK callers who
|
|
277
|
+
* batch recall calls in a row. Locked by
|
|
278
|
+
* `tests/api-recall-no-side-effects.test.ts`.
|
|
248
279
|
*/
|
|
249
280
|
export declare function recall(ctx: Context, opts: RecallOpts): RecallResult;
|
|
250
281
|
export interface AssembleOpts {
|
|
@@ -404,7 +435,7 @@ export declare function drillDown(ctx: Context, summaryId: string, opts?: DrillD
|
|
|
404
435
|
* Tenant-scoped: ids that don't belong to ctx.tenantId are silently skipped
|
|
405
436
|
* (matches the prior MCP semantics — a stale id from another tenant doesn't
|
|
406
437
|
* crash the call). Each successful outcome emits one audit_log row with
|
|
407
|
-
* op='outcome' tagged with ctx.actor.
|
|
438
|
+
* op='outcome' tagged with ctx.actor.subject.
|
|
408
439
|
*
|
|
409
440
|
* Returns `{applied, appliedIds}`. `appliedIds` is the tenant-filtered subset
|
|
410
441
|
* of input ids that actually had `applyOutcome` run on them (i.e. ids whose
|
|
@@ -419,7 +450,7 @@ export declare function outcome(ctx: Context, ids: ReadonlyArray<string>, good:
|
|
|
419
450
|
appliedIds: string[];
|
|
420
451
|
};
|
|
421
452
|
/**
|
|
422
|
-
* Delete a memory by id. `deleteEntry` threads ctx.actor into its internal
|
|
453
|
+
* Delete a memory by id. `deleteEntry` threads ctx.actor.subject into its internal
|
|
423
454
|
* audit hook, so exactly one 'forget' event lands with the supplied actor.
|
|
424
455
|
*
|
|
425
456
|
* Tenant scope: deleteEntry looks up the row by id alone, so without an
|
|
@@ -465,7 +496,7 @@ export declare function supersede(ctx: Context, oldId: string, newContent: strin
|
|
|
465
496
|
* `archiveRawMemory` audits the operation internally (op='archive_raw') using the
|
|
466
497
|
* row's own tenant_id. We DO NOT emit a second audit event here to avoid double-
|
|
467
498
|
* emitting the archive_raw op (unlike Task 1 remember/forget where the underlying
|
|
468
|
-
* helpers hardcode actor='cli'). Instead we pass `ctx.actor` through as `who`,
|
|
499
|
+
* helpers hardcode actor='cli'). Instead we pass `ctx.actor.subject` through as `who`,
|
|
469
500
|
* and raw-archive.ts uses that for the audit row.
|
|
470
501
|
*/
|
|
471
502
|
export interface ArchiveRawOpts {
|
package/dist/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAA6B,KAAK,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAC3E,OAAO,EAwBL,KAAK,YAAY,EACjB,KAAK,YAAY,EAClB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAIL,KAAK,UAAU,EACf,KAAK,WAAW,EAEjB,MAAM,aAAa,CAAC;AACrB,OAAO,EAIL,KAAK,UAAU,EACf,KAAK,OAAO,EACb,MAAM,YAAY,CAAC;AAGpB,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,WAAW,CAAC;AAOnB,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAEtE,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/api.js
CHANGED
|
@@ -21,6 +21,16 @@ import { consolidate } from './consolidate.js';
|
|
|
21
21
|
import { loadConfig } from './config.js';
|
|
22
22
|
import { deduplicateStore } from './dedupe.js';
|
|
23
23
|
import { computeAmbientState } from './ambient.js';
|
|
24
|
+
/**
|
|
25
|
+
* Helper for building process-local (admin-by-default) Actor values. v1.12.0
|
|
26
|
+
* factory used by CLI / MCP / connector Context constructors so the role
|
|
27
|
+
* boilerplate isn't repeated at every site. Bearer-authed callers (HTTP
|
|
28
|
+
* /v1/*) construct Actor directly from the api_keys row's role column via
|
|
29
|
+
* buildContextWithAuth in src/server.ts.
|
|
30
|
+
*/
|
|
31
|
+
export function adminActor(subject) {
|
|
32
|
+
return { subject, role: 'admin' };
|
|
33
|
+
}
|
|
24
34
|
/**
|
|
25
35
|
* Thrown by `api.recall` when a caller's options violate a recall contract
|
|
26
36
|
* that has been opted into via env. Carries a stable `code` field for HTTP /
|
|
@@ -105,9 +115,9 @@ export function remember(ctx, opts) {
|
|
|
105
115
|
tags: opts.tags,
|
|
106
116
|
tenantId: ctx.tenantId,
|
|
107
117
|
});
|
|
108
|
-
// writeEntry threads ctx.actor into its internal audit hook, so exactly
|
|
118
|
+
// writeEntry threads ctx.actor.subject into its internal audit hook, so exactly
|
|
109
119
|
// one 'remember' event lands in the log with the supplied actor.
|
|
110
|
-
writeEntry(ctx.hippoRoot, entry, { actor: ctx.actor, afterWrite: opts.afterWrite });
|
|
120
|
+
writeEntry(ctx.hippoRoot, entry, { actor: ctx.actor.subject, afterWrite: opts.afterWrite });
|
|
111
121
|
return { id: entry.id, kind: entry.kind, tenantId: ctx.tenantId };
|
|
112
122
|
}
|
|
113
123
|
/**
|
|
@@ -115,6 +125,16 @@ export function remember(ctx, opts) {
|
|
|
115
125
|
* `ctx.tenantId`. The `mode` flag is accepted for forward compatibility (the
|
|
116
126
|
* CLI exposes hybrid/physics paths) but Task 2 wires only the BM25 candidate
|
|
117
127
|
* loader; later tasks can extend this to call the physics/hybrid scorer.
|
|
128
|
+
*
|
|
129
|
+
* **api.recall does NOT mutate `index.last_retrieval_ids`** (v1.11.5 contract
|
|
130
|
+
* lock). The CLI `cmdRecall` (cli.ts) writes `last_retrieval_ids` because the
|
|
131
|
+
* CLI is interactive (user is about to run `hippo outcome --good`). SDK callers
|
|
132
|
+
* are programmatic: they either pass explicit ids to `api.outcome` or call
|
|
133
|
+
* `api.getContext` first for the context-then-outcome workflow (getContext
|
|
134
|
+
* DOES write `last_retrieval_ids`). Adding the side-effect here would change
|
|
135
|
+
* `api.recall` from a pure read into a read+write, breaking SDK callers who
|
|
136
|
+
* batch recall calls in a row. Locked by
|
|
137
|
+
* `tests/api-recall-no-side-effects.test.ts`.
|
|
118
138
|
*/
|
|
119
139
|
export function recall(ctx, opts) {
|
|
120
140
|
const limit = opts.limit ?? 10;
|
|
@@ -332,7 +352,7 @@ export function recall(ctx, opts) {
|
|
|
332
352
|
// long-prompt patterns and compliance metrics.
|
|
333
353
|
appendAuditEvent(db, {
|
|
334
354
|
tenantId: ctx.tenantId,
|
|
335
|
-
actor: ctx.actor,
|
|
355
|
+
actor: ctx.actor.subject,
|
|
336
356
|
op: 'recall',
|
|
337
357
|
metadata: {
|
|
338
358
|
query_hash: createHash('sha256').update(opts.query).digest('hex').slice(0, 16),
|
|
@@ -634,7 +654,7 @@ export function drillDown(ctx, summaryId, opts = {}) {
|
|
|
634
654
|
* Tenant-scoped: ids that don't belong to ctx.tenantId are silently skipped
|
|
635
655
|
* (matches the prior MCP semantics — a stale id from another tenant doesn't
|
|
636
656
|
* crash the call). Each successful outcome emits one audit_log row with
|
|
637
|
-
* op='outcome' tagged with ctx.actor.
|
|
657
|
+
* op='outcome' tagged with ctx.actor.subject.
|
|
638
658
|
*
|
|
639
659
|
* Returns `{applied, appliedIds}`. `appliedIds` is the tenant-filtered subset
|
|
640
660
|
* of input ids that actually had `applyOutcome` run on them (i.e. ids whose
|
|
@@ -653,10 +673,10 @@ export function outcome(ctx, ids, good) {
|
|
|
653
673
|
if (!entry)
|
|
654
674
|
continue;
|
|
655
675
|
const updated = applyOutcome(entry, good);
|
|
656
|
-
writeEntry(ctx.hippoRoot, updated, { actor: ctx.actor });
|
|
676
|
+
writeEntry(ctx.hippoRoot, updated, { actor: ctx.actor.subject });
|
|
657
677
|
appendAuditEvent(db, {
|
|
658
678
|
tenantId: ctx.tenantId,
|
|
659
|
-
actor: ctx.actor,
|
|
679
|
+
actor: ctx.actor.subject,
|
|
660
680
|
op: 'outcome',
|
|
661
681
|
targetId: id,
|
|
662
682
|
metadata: { good },
|
|
@@ -673,7 +693,7 @@ export function outcome(ctx, ids, good) {
|
|
|
673
693
|
// forget
|
|
674
694
|
// ---------------------------------------------------------------------------
|
|
675
695
|
/**
|
|
676
|
-
* Delete a memory by id. `deleteEntry` threads ctx.actor into its internal
|
|
696
|
+
* Delete a memory by id. `deleteEntry` threads ctx.actor.subject into its internal
|
|
677
697
|
* audit hook, so exactly one 'forget' event lands with the supplied actor.
|
|
678
698
|
*
|
|
679
699
|
* Tenant scope: deleteEntry looks up the row by id alone, so without an
|
|
@@ -695,7 +715,7 @@ export function forget(ctx, id) {
|
|
|
695
715
|
finally {
|
|
696
716
|
closeHippoDb(db);
|
|
697
717
|
}
|
|
698
|
-
const removed = deleteEntry(ctx.hippoRoot, id, { actor: ctx.actor });
|
|
718
|
+
const removed = deleteEntry(ctx.hippoRoot, id, { actor: ctx.actor.subject });
|
|
699
719
|
if (!removed) {
|
|
700
720
|
throw new Error(`memory not found: ${id}`);
|
|
701
721
|
}
|
|
@@ -734,16 +754,16 @@ export function promote(ctx, id) {
|
|
|
734
754
|
finally {
|
|
735
755
|
closeHippoDb(ownerDb);
|
|
736
756
|
}
|
|
737
|
-
// promoteToGlobal threads ctx.actor into the writeEntry call on the global
|
|
757
|
+
// promoteToGlobal threads ctx.actor.subject into the writeEntry call on the global
|
|
738
758
|
// db, which emits a 'remember' audit row. We then add the user-facing
|
|
739
759
|
// 'promote' event on the global db so the audit trail keeps the intent
|
|
740
760
|
// distinct from the underlying upsert.
|
|
741
|
-
const globalEntry = promoteToGlobal(ctx.hippoRoot, id, { actor: ctx.actor, tenantId: ctx.tenantId });
|
|
761
|
+
const globalEntry = promoteToGlobal(ctx.hippoRoot, id, { actor: ctx.actor.subject, tenantId: ctx.tenantId });
|
|
742
762
|
const db = openHippoDb(getGlobalRoot());
|
|
743
763
|
try {
|
|
744
764
|
appendAuditEvent(db, {
|
|
745
765
|
tenantId: ctx.tenantId,
|
|
746
|
-
actor: ctx.actor,
|
|
766
|
+
actor: ctx.actor.subject,
|
|
747
767
|
op: 'promote',
|
|
748
768
|
targetId: globalEntry.id,
|
|
749
769
|
metadata: { sourceId: id },
|
|
@@ -812,12 +832,12 @@ export function supersede(ctx, oldId, newContent) {
|
|
|
812
832
|
// 2. Write new memory inside same tx via writeEntryDbOnly (DB-only
|
|
813
833
|
// path). This emits its OWN 'remember' audit row for the new
|
|
814
834
|
// memory inside the SAVEPOINT — atomic with the row INSERT.
|
|
815
|
-
writeEntryDbOnly(db, newEntry, { actor: ctx.actor });
|
|
835
|
+
writeEntryDbOnly(db, newEntry, { actor: ctx.actor.subject });
|
|
816
836
|
// 3. User-facing 'supersede' audit row inside the same tx so the
|
|
817
837
|
// chain pointer + audit trail commit atomically.
|
|
818
838
|
appendAuditEvent(db, {
|
|
819
839
|
tenantId: ctx.tenantId,
|
|
820
|
-
actor: ctx.actor,
|
|
840
|
+
actor: ctx.actor.subject,
|
|
821
841
|
op: 'supersede',
|
|
822
842
|
targetId: oldId,
|
|
823
843
|
metadata: { newId: newEntry.id },
|
|
@@ -865,7 +885,7 @@ export function archiveRaw(ctx, id, reason, opts = {}) {
|
|
|
865
885
|
}
|
|
866
886
|
archiveRawMemory(db, id, {
|
|
867
887
|
reason,
|
|
868
|
-
who: ctx.actor,
|
|
888
|
+
who: ctx.actor.subject,
|
|
869
889
|
afterArchive: opts.afterArchive,
|
|
870
890
|
});
|
|
871
891
|
// archiveRawMemory deletes the memories row but leaves any legacy markdown
|
|
@@ -980,7 +1000,7 @@ export function authRevoke(ctx, keyId) {
|
|
|
980
1000
|
try {
|
|
981
1001
|
appendAuditEvent(db, {
|
|
982
1002
|
tenantId: row.tenant_id, // M1: KEY's tenant, not ctx.tenantId.
|
|
983
|
-
actor: ctx.actor,
|
|
1003
|
+
actor: ctx.actor.subject,
|
|
984
1004
|
op: 'auth_revoke',
|
|
985
1005
|
targetId: keyId,
|
|
986
1006
|
});
|
|
@@ -1226,7 +1246,7 @@ export async function getContext(ctx, opts = {}) {
|
|
|
1226
1246
|
try {
|
|
1227
1247
|
appendAuditEvent(localDb, {
|
|
1228
1248
|
tenantId: ctx.tenantId,
|
|
1229
|
-
actor: ctx.actor,
|
|
1249
|
+
actor: ctx.actor.subject,
|
|
1230
1250
|
op: 'recall',
|
|
1231
1251
|
metadata: ctxRecallMetadata,
|
|
1232
1252
|
});
|
|
@@ -1240,7 +1260,7 @@ export async function getContext(ctx, opts = {}) {
|
|
|
1240
1260
|
try {
|
|
1241
1261
|
appendAuditEvent(globalDb, {
|
|
1242
1262
|
tenantId: ctx.tenantId,
|
|
1243
|
-
actor: ctx.actor,
|
|
1263
|
+
actor: ctx.actor.subject,
|
|
1244
1264
|
op: 'recall',
|
|
1245
1265
|
metadata: ctxRecallMetadata,
|
|
1246
1266
|
});
|
|
@@ -1312,68 +1332,139 @@ export async function getContext(ctx, opts = {}) {
|
|
|
1312
1332
|
*/
|
|
1313
1333
|
export async function sleep(ctx, opts = {}) {
|
|
1314
1334
|
const dryRun = Boolean(opts.dryRun);
|
|
1315
|
-
//
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
semDups,
|
|
1336
|
-
epiDups,
|
|
1337
|
-
crossDups,
|
|
1335
|
+
// v1.11.5: phase counters for the consolidate audit emit (in finally).
|
|
1336
|
+
// Accumulated as each phase completes so partial-failure paths still report
|
|
1337
|
+
// accurate "what got done before the failure" data.
|
|
1338
|
+
let consolidationCount = 0;
|
|
1339
|
+
let dedupCount = 0;
|
|
1340
|
+
let auditDeletedCount = 0;
|
|
1341
|
+
let ambientTotal = 0;
|
|
1342
|
+
let phaseError = null;
|
|
1343
|
+
let result = null;
|
|
1344
|
+
try {
|
|
1345
|
+
// Phase 1: Consolidation.
|
|
1346
|
+
const consolidateResult = await consolidate(ctx.hippoRoot, { dryRun });
|
|
1347
|
+
consolidationCount = consolidateResult.semanticCreated + consolidateResult.merged;
|
|
1348
|
+
result = {
|
|
1349
|
+
active: consolidateResult.decayed,
|
|
1350
|
+
removed: consolidateResult.removed,
|
|
1351
|
+
mergedEpisodic: consolidateResult.merged,
|
|
1352
|
+
newSemantic: consolidateResult.semanticCreated,
|
|
1353
|
+
dryRun,
|
|
1354
|
+
details: consolidateResult.details,
|
|
1338
1355
|
};
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1356
|
+
if (dryRun)
|
|
1357
|
+
return result;
|
|
1358
|
+
// Phase 2: Dedup (post-consolidate near-duplicate cleanup).
|
|
1359
|
+
const dedupResult = deduplicateStore(ctx.hippoRoot);
|
|
1360
|
+
dedupCount = dedupResult.removed;
|
|
1361
|
+
if (dedupResult.removed > 0) {
|
|
1362
|
+
const semDups = dedupResult.pairs.filter((p) => p.keptLayer === 'semantic' && p.removedLayer === 'semantic').length;
|
|
1363
|
+
const epiDups = dedupResult.pairs.filter((p) => p.keptLayer === 'episodic' && p.removedLayer === 'episodic').length;
|
|
1364
|
+
const crossDups = dedupResult.pairs.filter((p) => p.keptLayer !== p.removedLayer).length;
|
|
1365
|
+
result.deduped = {
|
|
1366
|
+
removed: dedupResult.removed,
|
|
1367
|
+
semDups,
|
|
1368
|
+
epiDups,
|
|
1369
|
+
crossDups,
|
|
1370
|
+
};
|
|
1371
|
+
}
|
|
1372
|
+
// Phase 3: Quality audit (remove junk, report warnings).
|
|
1373
|
+
const allEntries = loadAllEntries(ctx.hippoRoot);
|
|
1374
|
+
const auditOut = auditMemories(allEntries);
|
|
1375
|
+
if (auditOut.issues.length > 0) {
|
|
1376
|
+
const errors = auditOut.issues.filter((i) => i.severity === 'error');
|
|
1377
|
+
const warnings = auditOut.issues.filter((i) => i.severity === 'warning');
|
|
1378
|
+
if (errors.length > 0) {
|
|
1379
|
+
for (const issue of errors) {
|
|
1380
|
+
deleteEntry(ctx.hippoRoot, issue.memoryId);
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
auditDeletedCount = errors.length;
|
|
1384
|
+
if (errors.length > 0 || warnings.length > 0) {
|
|
1385
|
+
result.audit = {
|
|
1386
|
+
errorsRemoved: errors.length,
|
|
1387
|
+
warningCount: warnings.length,
|
|
1388
|
+
};
|
|
1349
1389
|
}
|
|
1350
1390
|
}
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1391
|
+
// Phase 4: Auto-share high-transfer-score memories to global.
|
|
1392
|
+
if (!opts.noShare) {
|
|
1393
|
+
const sleepConfig = loadConfig(ctx.hippoRoot);
|
|
1394
|
+
if (sleepConfig.autoShareOnSleep) {
|
|
1395
|
+
const shared = autoShare(ctx.hippoRoot, { minScore: 0.6 });
|
|
1396
|
+
if (shared.length > 0) {
|
|
1397
|
+
result.shared = shared.length;
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1356
1400
|
}
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
result.shared = shared.length;
|
|
1401
|
+
// Phase 5: Post-sleep ambient state summary.
|
|
1402
|
+
const postSleepConfig = loadConfig(ctx.hippoRoot);
|
|
1403
|
+
if (postSleepConfig.ambient.enabled) {
|
|
1404
|
+
const postSleepEntries = loadAllEntries(ctx.hippoRoot).filter((e) => !e.superseded_by);
|
|
1405
|
+
if (postSleepEntries.length > 0) {
|
|
1406
|
+
result.ambient = computeAmbientState(postSleepEntries);
|
|
1407
|
+
ambientTotal = result.ambient.totalMemories;
|
|
1365
1408
|
}
|
|
1366
1409
|
}
|
|
1410
|
+
return result;
|
|
1411
|
+
}
|
|
1412
|
+
catch (err) {
|
|
1413
|
+
phaseError = err;
|
|
1414
|
+
throw err;
|
|
1367
1415
|
}
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1416
|
+
finally {
|
|
1417
|
+
// v1.11.5: emit one 'consolidate' audit_log row per api.sleep invocation,
|
|
1418
|
+
// with phase counters in metadata. Closes the CLI/MCP parity gap that T6
|
|
1419
|
+
// fixed for cmdOutcome (Episode A follow-up). In finally so partial-failure
|
|
1420
|
+
// paths still emit; `partial: true` + errorMessage flag the failure.
|
|
1421
|
+
// Dedicated handle for this emit only (phase helpers above each open their
|
|
1422
|
+
// own handle via hippoRoot — SQLite single-writer makes parallel handles
|
|
1423
|
+
// safe for the read-heavy phases).
|
|
1424
|
+
//
|
|
1425
|
+
// TODO(v1.12.0 + A5 v2): the audit row is tagged with ctx.tenantId but
|
|
1426
|
+
// api.sleep is host-wide (cross-tenant dedup is intentional). When
|
|
1427
|
+
// /v1/sleep moves off loopback-only, either tag with a synthetic "host"
|
|
1428
|
+
// tenant or scope api.sleep per-tenant. Independent-review-critic flag,
|
|
1429
|
+
// v1.11.5 ship.
|
|
1430
|
+
//
|
|
1431
|
+
// Error preservation: if openHippoDb or appendAuditEvent throws here, we
|
|
1432
|
+
// do NOT let it replace the original phaseError (independent-review HIGH:
|
|
1433
|
+
// would mask the underlying consolidation failure). Audit emit failure
|
|
1434
|
+
// is logged to stderr but the original throw wins.
|
|
1435
|
+
try {
|
|
1436
|
+
const db = openHippoDb(ctx.hippoRoot);
|
|
1437
|
+
try {
|
|
1438
|
+
appendAuditEvent(db, {
|
|
1439
|
+
tenantId: ctx.tenantId,
|
|
1440
|
+
actor: ctx.actor.subject,
|
|
1441
|
+
op: 'consolidate',
|
|
1442
|
+
metadata: {
|
|
1443
|
+
consolidationCount,
|
|
1444
|
+
dedupCount,
|
|
1445
|
+
auditDeletedCount,
|
|
1446
|
+
ambientTotal,
|
|
1447
|
+
dryRun,
|
|
1448
|
+
noShare: opts.noShare ?? false,
|
|
1449
|
+
partial: phaseError !== null,
|
|
1450
|
+
...(phaseError ? { errorMessage: phaseError.message } : {}),
|
|
1451
|
+
},
|
|
1452
|
+
});
|
|
1453
|
+
}
|
|
1454
|
+
finally {
|
|
1455
|
+
closeHippoDb(db);
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
catch (auditErr) {
|
|
1459
|
+
// Audit emit failure must NOT mask the original phaseError. Log to
|
|
1460
|
+
// stderr so the secondary failure is observable but does not throw.
|
|
1461
|
+
// This guards the case where consolidation AND audit-emit fail in the
|
|
1462
|
+
// same invocation against the same DB (correlated: same disk, same
|
|
1463
|
+
// schema state) — losing the original error makes diagnosis much harder.
|
|
1464
|
+
// eslint-disable-next-line no-console
|
|
1465
|
+
console.error(`[hippo] api.sleep audit emit failed: ${auditErr.message}`);
|
|
1374
1466
|
}
|
|
1375
1467
|
}
|
|
1376
|
-
return result;
|
|
1377
1468
|
}
|
|
1378
1469
|
// ---------------------------------------------------------------------------
|
|
1379
1470
|
// outcomeForLastRecall (last-recall wrapper around outcome — Task 3)
|