hippo-memory 1.11.3 → 1.11.5
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 +41 -12
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +169 -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/cli.d.ts +15 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +10 -3
- package/dist/cli.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +137 -1
- package/dist/server.js.map +1 -1
- package/dist/src/api.js +169 -70
- package/dist/src/api.js.map +1 -1
- package/dist/src/audit.js.map +1 -1
- package/dist/src/cli.js +10 -3
- package/dist/src/cli.js.map +1 -1
- package/dist/src/server.js +137 -1
- 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
|
@@ -245,6 +245,16 @@ export interface RecallResult {
|
|
|
245
245
|
* `ctx.tenantId`. The `mode` flag is accepted for forward compatibility (the
|
|
246
246
|
* CLI exposes hybrid/physics paths) but Task 2 wires only the BM25 candidate
|
|
247
247
|
* loader; later tasks can extend this to call the physics/hybrid scorer.
|
|
248
|
+
*
|
|
249
|
+
* **api.recall does NOT mutate `index.last_retrieval_ids`** (v1.11.5 contract
|
|
250
|
+
* lock). The CLI `cmdRecall` (cli.ts) writes `last_retrieval_ids` because the
|
|
251
|
+
* CLI is interactive (user is about to run `hippo outcome --good`). SDK callers
|
|
252
|
+
* are programmatic: they either pass explicit ids to `api.outcome` or call
|
|
253
|
+
* `api.getContext` first for the context-then-outcome workflow (getContext
|
|
254
|
+
* DOES write `last_retrieval_ids`). Adding the side-effect here would change
|
|
255
|
+
* `api.recall` from a pure read into a read+write, breaking SDK callers who
|
|
256
|
+
* batch recall calls in a row. Locked by
|
|
257
|
+
* `tests/api-recall-no-side-effects.test.ts`.
|
|
248
258
|
*/
|
|
249
259
|
export declare function recall(ctx: Context, opts: RecallOpts): RecallResult;
|
|
250
260
|
export interface AssembleOpts {
|
|
@@ -400,13 +410,23 @@ export type DrillDownOutcome = DrillDownResult | DrillDownFailure;
|
|
|
400
410
|
export declare function drillDown(ctx: Context, summaryId: string, opts?: DrillDownOpts): DrillDownOutcome;
|
|
401
411
|
/**
|
|
402
412
|
* Apply a positive/negative outcome to a list of recently-recalled memory ids.
|
|
403
|
-
* Used by the MCP `hippo_outcome` tool
|
|
404
|
-
* to ctx.tenantId are silently skipped
|
|
405
|
-
* a stale id from another tenant doesn't
|
|
406
|
-
* outcome emits one audit_log row with
|
|
413
|
+
* Used by the MCP `hippo_outcome` tool and the HTTP `POST /v1/outcome` route.
|
|
414
|
+
* Tenant-scoped: ids that don't belong to ctx.tenantId are silently skipped
|
|
415
|
+
* (matches the prior MCP semantics — a stale id from another tenant doesn't
|
|
416
|
+
* crash the call). Each successful outcome emits one audit_log row with
|
|
417
|
+
* op='outcome' tagged with ctx.actor.
|
|
418
|
+
*
|
|
419
|
+
* Returns `{applied, appliedIds}`. `appliedIds` is the tenant-filtered subset
|
|
420
|
+
* of input ids that actually had `applyOutcome` run on them (i.e. ids whose
|
|
421
|
+
* `readEntry(..., ctx.tenantId)` resolved). Callers that surface the id list
|
|
422
|
+
* over a multi-tenant boundary (HTTP /v1/outcome last-recall path, Python SDK)
|
|
423
|
+
* MUST return `appliedIds` instead of the raw input list — otherwise the
|
|
424
|
+
* non-applied (cross-tenant) ids leak to the caller. Added in v1.11.4 to
|
|
425
|
+
* close that disclosure path on POST /v1/outcome.
|
|
407
426
|
*/
|
|
408
427
|
export declare function outcome(ctx: Context, ids: ReadonlyArray<string>, good: boolean): {
|
|
409
428
|
applied: number;
|
|
429
|
+
appliedIds: string[];
|
|
410
430
|
};
|
|
411
431
|
/**
|
|
412
432
|
* Delete a memory by id. `deleteEntry` threads ctx.actor into its internal
|
|
@@ -628,17 +648,17 @@ export interface SleepResult {
|
|
|
628
648
|
*
|
|
629
649
|
* Tenant scope note: sleep operates on the WHOLE hippoRoot (all tenants in
|
|
630
650
|
* it), matching the pre-refactor cmdSleepCore behavior. Correct for a CLI
|
|
631
|
-
* maintenance op invoked by the operator.
|
|
632
|
-
* over HTTP `/v1/sleep
|
|
633
|
-
*
|
|
634
|
-
*
|
|
635
|
-
*
|
|
651
|
+
* maintenance op invoked by the operator. Episode B (v1.11.4) exposed this
|
|
652
|
+
* over HTTP `/v1/sleep` with loopback-only enforcement (per-request guard
|
|
653
|
+
* in the handler plus serve()'s boot-time host check). The TODOS.md
|
|
654
|
+
* per-tenant scoping follow-up remains open for the day non-loopback
|
|
655
|
+
* serving lands — at that point the route will need an admin-role gate OR
|
|
656
|
+
* api.sleep itself will need to scope dedup / audit / delete by ctx.tenantId.
|
|
636
657
|
*
|
|
637
658
|
* Audit emission gap: the consolidation phases (dedup, audit-delete) do
|
|
638
659
|
* NOT emit audit_log rows today, matching pre-refactor cmdSleepCore. Same
|
|
639
660
|
* CLI/MCP parity gap that T6 fixed for cmdOutcome, now visible at the api
|
|
640
|
-
* surface.
|
|
641
|
-
* 'consolidate' audit row per invocation or per-phase rows per deletion.
|
|
661
|
+
* surface. Tracked in TODOS.md "Episode A follow-ups" for a future minor.
|
|
642
662
|
*/
|
|
643
663
|
export declare function sleep(ctx: Context, opts?: SleepOpts): Promise<SleepResult>;
|
|
644
664
|
/**
|
|
@@ -646,10 +666,19 @@ export declare function sleep(ctx: Context, opts?: SleepOpts): Promise<SleepResu
|
|
|
646
666
|
*
|
|
647
667
|
* Reads `loadIndex(ctx.hippoRoot).last_retrieval_ids` (per-hippoRoot local
|
|
648
668
|
* state; not tenant-scoped at the index layer) and forwards to `outcome()`,
|
|
649
|
-
* which DOES tenant-filter via `readEntry(..., ctx.tenantId)
|
|
669
|
+
* which DOES tenant-filter via `readEntry(..., ctx.tenantId)`. Cross-tenant
|
|
650
670
|
* ids in `last_retrieval_ids` are silently skipped, matching the MCP
|
|
651
671
|
* `hippo_outcome` semantics.
|
|
652
672
|
*
|
|
673
|
+
* **Tenant-safe response shape (v1.11.4 security fix):** the returned `ids`
|
|
674
|
+
* field contains ONLY the tenant-filtered subset that actually had outcomes
|
|
675
|
+
* applied (i.e. `appliedIds` from the inner `outcome()` call). Earlier
|
|
676
|
+
* versions returned the raw `last_retrieval_ids` regardless of tenant, which
|
|
677
|
+
* leaked cross-tenant memory IDs to the caller via POST /v1/outcome's
|
|
678
|
+
* no-body last-recall response. The fix is at this helper so all callers
|
|
679
|
+
* (CLI cmdOutcome, HTTP /v1/outcome, MCP `hippo_outcome` if added later)
|
|
680
|
+
* inherit the tenant-safe contract.
|
|
681
|
+
*
|
|
653
682
|
* Do NOT tighten `loadIndex` with `tenantId` inside this helper — doing so
|
|
654
683
|
* would break the (correct) cross-tenant-silent-skip behavior covered by
|
|
655
684
|
* the test in `tests/api-outcome-for-last-recall.test.ts`.
|
package/dist/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/api.js
CHANGED
|
@@ -115,6 +115,16 @@ export function remember(ctx, opts) {
|
|
|
115
115
|
* `ctx.tenantId`. The `mode` flag is accepted for forward compatibility (the
|
|
116
116
|
* CLI exposes hybrid/physics paths) but Task 2 wires only the BM25 candidate
|
|
117
117
|
* loader; later tasks can extend this to call the physics/hybrid scorer.
|
|
118
|
+
*
|
|
119
|
+
* **api.recall does NOT mutate `index.last_retrieval_ids`** (v1.11.5 contract
|
|
120
|
+
* lock). The CLI `cmdRecall` (cli.ts) writes `last_retrieval_ids` because the
|
|
121
|
+
* CLI is interactive (user is about to run `hippo outcome --good`). SDK callers
|
|
122
|
+
* are programmatic: they either pass explicit ids to `api.outcome` or call
|
|
123
|
+
* `api.getContext` first for the context-then-outcome workflow (getContext
|
|
124
|
+
* DOES write `last_retrieval_ids`). Adding the side-effect here would change
|
|
125
|
+
* `api.recall` from a pure read into a read+write, breaking SDK callers who
|
|
126
|
+
* batch recall calls in a row. Locked by
|
|
127
|
+
* `tests/api-recall-no-side-effects.test.ts`.
|
|
118
128
|
*/
|
|
119
129
|
export function recall(ctx, opts) {
|
|
120
130
|
const limit = opts.limit ?? 10;
|
|
@@ -630,13 +640,22 @@ export function drillDown(ctx, summaryId, opts = {}) {
|
|
|
630
640
|
// ---------------------------------------------------------------------------
|
|
631
641
|
/**
|
|
632
642
|
* Apply a positive/negative outcome to a list of recently-recalled memory ids.
|
|
633
|
-
* Used by the MCP `hippo_outcome` tool
|
|
634
|
-
* to ctx.tenantId are silently skipped
|
|
635
|
-
* a stale id from another tenant doesn't
|
|
636
|
-
* outcome emits one audit_log row with
|
|
643
|
+
* Used by the MCP `hippo_outcome` tool and the HTTP `POST /v1/outcome` route.
|
|
644
|
+
* Tenant-scoped: ids that don't belong to ctx.tenantId are silently skipped
|
|
645
|
+
* (matches the prior MCP semantics — a stale id from another tenant doesn't
|
|
646
|
+
* crash the call). Each successful outcome emits one audit_log row with
|
|
647
|
+
* op='outcome' tagged with ctx.actor.
|
|
648
|
+
*
|
|
649
|
+
* Returns `{applied, appliedIds}`. `appliedIds` is the tenant-filtered subset
|
|
650
|
+
* of input ids that actually had `applyOutcome` run on them (i.e. ids whose
|
|
651
|
+
* `readEntry(..., ctx.tenantId)` resolved). Callers that surface the id list
|
|
652
|
+
* over a multi-tenant boundary (HTTP /v1/outcome last-recall path, Python SDK)
|
|
653
|
+
* MUST return `appliedIds` instead of the raw input list — otherwise the
|
|
654
|
+
* non-applied (cross-tenant) ids leak to the caller. Added in v1.11.4 to
|
|
655
|
+
* close that disclosure path on POST /v1/outcome.
|
|
637
656
|
*/
|
|
638
657
|
export function outcome(ctx, ids, good) {
|
|
639
|
-
|
|
658
|
+
const appliedIds = [];
|
|
640
659
|
const db = openHippoDb(ctx.hippoRoot);
|
|
641
660
|
try {
|
|
642
661
|
for (const id of ids) {
|
|
@@ -652,13 +671,13 @@ export function outcome(ctx, ids, good) {
|
|
|
652
671
|
targetId: id,
|
|
653
672
|
metadata: { good },
|
|
654
673
|
});
|
|
655
|
-
|
|
674
|
+
appliedIds.push(id);
|
|
656
675
|
}
|
|
657
676
|
}
|
|
658
677
|
finally {
|
|
659
678
|
closeHippoDb(db);
|
|
660
679
|
}
|
|
661
|
-
return { applied };
|
|
680
|
+
return { applied: appliedIds.length, appliedIds };
|
|
662
681
|
}
|
|
663
682
|
// ---------------------------------------------------------------------------
|
|
664
683
|
// forget
|
|
@@ -1289,82 +1308,153 @@ export async function getContext(ctx, opts = {}) {
|
|
|
1289
1308
|
*
|
|
1290
1309
|
* Tenant scope note: sleep operates on the WHOLE hippoRoot (all tenants in
|
|
1291
1310
|
* it), matching the pre-refactor cmdSleepCore behavior. Correct for a CLI
|
|
1292
|
-
* maintenance op invoked by the operator.
|
|
1293
|
-
* over HTTP `/v1/sleep
|
|
1294
|
-
*
|
|
1295
|
-
*
|
|
1296
|
-
*
|
|
1311
|
+
* maintenance op invoked by the operator. Episode B (v1.11.4) exposed this
|
|
1312
|
+
* over HTTP `/v1/sleep` with loopback-only enforcement (per-request guard
|
|
1313
|
+
* in the handler plus serve()'s boot-time host check). The TODOS.md
|
|
1314
|
+
* per-tenant scoping follow-up remains open for the day non-loopback
|
|
1315
|
+
* serving lands — at that point the route will need an admin-role gate OR
|
|
1316
|
+
* api.sleep itself will need to scope dedup / audit / delete by ctx.tenantId.
|
|
1297
1317
|
*
|
|
1298
1318
|
* Audit emission gap: the consolidation phases (dedup, audit-delete) do
|
|
1299
1319
|
* NOT emit audit_log rows today, matching pre-refactor cmdSleepCore. Same
|
|
1300
1320
|
* CLI/MCP parity gap that T6 fixed for cmdOutcome, now visible at the api
|
|
1301
|
-
* surface.
|
|
1302
|
-
* 'consolidate' audit row per invocation or per-phase rows per deletion.
|
|
1321
|
+
* surface. Tracked in TODOS.md "Episode A follow-ups" for a future minor.
|
|
1303
1322
|
*/
|
|
1304
1323
|
export async function sleep(ctx, opts = {}) {
|
|
1305
1324
|
const dryRun = Boolean(opts.dryRun);
|
|
1306
|
-
//
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
semDups,
|
|
1327
|
-
epiDups,
|
|
1328
|
-
crossDups,
|
|
1325
|
+
// v1.11.5: phase counters for the consolidate audit emit (in finally).
|
|
1326
|
+
// Accumulated as each phase completes so partial-failure paths still report
|
|
1327
|
+
// accurate "what got done before the failure" data.
|
|
1328
|
+
let consolidationCount = 0;
|
|
1329
|
+
let dedupCount = 0;
|
|
1330
|
+
let auditDeletedCount = 0;
|
|
1331
|
+
let ambientTotal = 0;
|
|
1332
|
+
let phaseError = null;
|
|
1333
|
+
let result = null;
|
|
1334
|
+
try {
|
|
1335
|
+
// Phase 1: Consolidation.
|
|
1336
|
+
const consolidateResult = await consolidate(ctx.hippoRoot, { dryRun });
|
|
1337
|
+
consolidationCount = consolidateResult.semanticCreated + consolidateResult.merged;
|
|
1338
|
+
result = {
|
|
1339
|
+
active: consolidateResult.decayed,
|
|
1340
|
+
removed: consolidateResult.removed,
|
|
1341
|
+
mergedEpisodic: consolidateResult.merged,
|
|
1342
|
+
newSemantic: consolidateResult.semanticCreated,
|
|
1343
|
+
dryRun,
|
|
1344
|
+
details: consolidateResult.details,
|
|
1329
1345
|
};
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1346
|
+
if (dryRun)
|
|
1347
|
+
return result;
|
|
1348
|
+
// Phase 2: Dedup (post-consolidate near-duplicate cleanup).
|
|
1349
|
+
const dedupResult = deduplicateStore(ctx.hippoRoot);
|
|
1350
|
+
dedupCount = dedupResult.removed;
|
|
1351
|
+
if (dedupResult.removed > 0) {
|
|
1352
|
+
const semDups = dedupResult.pairs.filter((p) => p.keptLayer === 'semantic' && p.removedLayer === 'semantic').length;
|
|
1353
|
+
const epiDups = dedupResult.pairs.filter((p) => p.keptLayer === 'episodic' && p.removedLayer === 'episodic').length;
|
|
1354
|
+
const crossDups = dedupResult.pairs.filter((p) => p.keptLayer !== p.removedLayer).length;
|
|
1355
|
+
result.deduped = {
|
|
1356
|
+
removed: dedupResult.removed,
|
|
1357
|
+
semDups,
|
|
1358
|
+
epiDups,
|
|
1359
|
+
crossDups,
|
|
1360
|
+
};
|
|
1361
|
+
}
|
|
1362
|
+
// Phase 3: Quality audit (remove junk, report warnings).
|
|
1363
|
+
const allEntries = loadAllEntries(ctx.hippoRoot);
|
|
1364
|
+
const auditOut = auditMemories(allEntries);
|
|
1365
|
+
if (auditOut.issues.length > 0) {
|
|
1366
|
+
const errors = auditOut.issues.filter((i) => i.severity === 'error');
|
|
1367
|
+
const warnings = auditOut.issues.filter((i) => i.severity === 'warning');
|
|
1368
|
+
if (errors.length > 0) {
|
|
1369
|
+
for (const issue of errors) {
|
|
1370
|
+
deleteEntry(ctx.hippoRoot, issue.memoryId);
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
auditDeletedCount = errors.length;
|
|
1374
|
+
if (errors.length > 0 || warnings.length > 0) {
|
|
1375
|
+
result.audit = {
|
|
1376
|
+
errorsRemoved: errors.length,
|
|
1377
|
+
warningCount: warnings.length,
|
|
1378
|
+
};
|
|
1340
1379
|
}
|
|
1341
1380
|
}
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1381
|
+
// Phase 4: Auto-share high-transfer-score memories to global.
|
|
1382
|
+
if (!opts.noShare) {
|
|
1383
|
+
const sleepConfig = loadConfig(ctx.hippoRoot);
|
|
1384
|
+
if (sleepConfig.autoShareOnSleep) {
|
|
1385
|
+
const shared = autoShare(ctx.hippoRoot, { minScore: 0.6 });
|
|
1386
|
+
if (shared.length > 0) {
|
|
1387
|
+
result.shared = shared.length;
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1347
1390
|
}
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
result.shared = shared.length;
|
|
1391
|
+
// Phase 5: Post-sleep ambient state summary.
|
|
1392
|
+
const postSleepConfig = loadConfig(ctx.hippoRoot);
|
|
1393
|
+
if (postSleepConfig.ambient.enabled) {
|
|
1394
|
+
const postSleepEntries = loadAllEntries(ctx.hippoRoot).filter((e) => !e.superseded_by);
|
|
1395
|
+
if (postSleepEntries.length > 0) {
|
|
1396
|
+
result.ambient = computeAmbientState(postSleepEntries);
|
|
1397
|
+
ambientTotal = result.ambient.totalMemories;
|
|
1356
1398
|
}
|
|
1357
1399
|
}
|
|
1400
|
+
return result;
|
|
1401
|
+
}
|
|
1402
|
+
catch (err) {
|
|
1403
|
+
phaseError = err;
|
|
1404
|
+
throw err;
|
|
1358
1405
|
}
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1406
|
+
finally {
|
|
1407
|
+
// v1.11.5: emit one 'consolidate' audit_log row per api.sleep invocation,
|
|
1408
|
+
// with phase counters in metadata. Closes the CLI/MCP parity gap that T6
|
|
1409
|
+
// fixed for cmdOutcome (Episode A follow-up). In finally so partial-failure
|
|
1410
|
+
// paths still emit; `partial: true` + errorMessage flag the failure.
|
|
1411
|
+
// Dedicated handle for this emit only (phase helpers above each open their
|
|
1412
|
+
// own handle via hippoRoot — SQLite single-writer makes parallel handles
|
|
1413
|
+
// safe for the read-heavy phases).
|
|
1414
|
+
//
|
|
1415
|
+
// TODO(v1.12.0 + A5 v2): the audit row is tagged with ctx.tenantId but
|
|
1416
|
+
// api.sleep is host-wide (cross-tenant dedup is intentional). When
|
|
1417
|
+
// /v1/sleep moves off loopback-only, either tag with a synthetic "host"
|
|
1418
|
+
// tenant or scope api.sleep per-tenant. Independent-review-critic flag,
|
|
1419
|
+
// v1.11.5 ship.
|
|
1420
|
+
//
|
|
1421
|
+
// Error preservation: if openHippoDb or appendAuditEvent throws here, we
|
|
1422
|
+
// do NOT let it replace the original phaseError (independent-review HIGH:
|
|
1423
|
+
// would mask the underlying consolidation failure). Audit emit failure
|
|
1424
|
+
// is logged to stderr but the original throw wins.
|
|
1425
|
+
try {
|
|
1426
|
+
const db = openHippoDb(ctx.hippoRoot);
|
|
1427
|
+
try {
|
|
1428
|
+
appendAuditEvent(db, {
|
|
1429
|
+
tenantId: ctx.tenantId,
|
|
1430
|
+
actor: ctx.actor,
|
|
1431
|
+
op: 'consolidate',
|
|
1432
|
+
metadata: {
|
|
1433
|
+
consolidationCount,
|
|
1434
|
+
dedupCount,
|
|
1435
|
+
auditDeletedCount,
|
|
1436
|
+
ambientTotal,
|
|
1437
|
+
dryRun,
|
|
1438
|
+
noShare: opts.noShare ?? false,
|
|
1439
|
+
partial: phaseError !== null,
|
|
1440
|
+
...(phaseError ? { errorMessage: phaseError.message } : {}),
|
|
1441
|
+
},
|
|
1442
|
+
});
|
|
1443
|
+
}
|
|
1444
|
+
finally {
|
|
1445
|
+
closeHippoDb(db);
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
catch (auditErr) {
|
|
1449
|
+
// Audit emit failure must NOT mask the original phaseError. Log to
|
|
1450
|
+
// stderr so the secondary failure is observable but does not throw.
|
|
1451
|
+
// This guards the case where consolidation AND audit-emit fail in the
|
|
1452
|
+
// same invocation against the same DB (correlated: same disk, same
|
|
1453
|
+
// schema state) — losing the original error makes diagnosis much harder.
|
|
1454
|
+
// eslint-disable-next-line no-console
|
|
1455
|
+
console.error(`[hippo] api.sleep audit emit failed: ${auditErr.message}`);
|
|
1365
1456
|
}
|
|
1366
1457
|
}
|
|
1367
|
-
return result;
|
|
1368
1458
|
}
|
|
1369
1459
|
// ---------------------------------------------------------------------------
|
|
1370
1460
|
// outcomeForLastRecall (last-recall wrapper around outcome — Task 3)
|
|
@@ -1374,10 +1464,19 @@ export async function sleep(ctx, opts = {}) {
|
|
|
1374
1464
|
*
|
|
1375
1465
|
* Reads `loadIndex(ctx.hippoRoot).last_retrieval_ids` (per-hippoRoot local
|
|
1376
1466
|
* state; not tenant-scoped at the index layer) and forwards to `outcome()`,
|
|
1377
|
-
* which DOES tenant-filter via `readEntry(..., ctx.tenantId)
|
|
1467
|
+
* which DOES tenant-filter via `readEntry(..., ctx.tenantId)`. Cross-tenant
|
|
1378
1468
|
* ids in `last_retrieval_ids` are silently skipped, matching the MCP
|
|
1379
1469
|
* `hippo_outcome` semantics.
|
|
1380
1470
|
*
|
|
1471
|
+
* **Tenant-safe response shape (v1.11.4 security fix):** the returned `ids`
|
|
1472
|
+
* field contains ONLY the tenant-filtered subset that actually had outcomes
|
|
1473
|
+
* applied (i.e. `appliedIds` from the inner `outcome()` call). Earlier
|
|
1474
|
+
* versions returned the raw `last_retrieval_ids` regardless of tenant, which
|
|
1475
|
+
* leaked cross-tenant memory IDs to the caller via POST /v1/outcome's
|
|
1476
|
+
* no-body last-recall response. The fix is at this helper so all callers
|
|
1477
|
+
* (CLI cmdOutcome, HTTP /v1/outcome, MCP `hippo_outcome` if added later)
|
|
1478
|
+
* inherit the tenant-safe contract.
|
|
1479
|
+
*
|
|
1381
1480
|
* Do NOT tighten `loadIndex` with `tenantId` inside this helper — doing so
|
|
1382
1481
|
* would break the (correct) cross-tenant-silent-skip behavior covered by
|
|
1383
1482
|
* the test in `tests/api-outcome-for-last-recall.test.ts`.
|
|
@@ -1387,7 +1486,7 @@ export function outcomeForLastRecall(ctx, good) {
|
|
|
1387
1486
|
const ids = idx.last_retrieval_ids;
|
|
1388
1487
|
if (ids.length === 0)
|
|
1389
1488
|
return { applied: 0, ids: [] };
|
|
1390
|
-
const { applied } = outcome(ctx, ids, good);
|
|
1391
|
-
return { applied, ids };
|
|
1489
|
+
const { applied, appliedIds } = outcome(ctx, ids, good);
|
|
1490
|
+
return { applied, ids: appliedIds };
|
|
1392
1491
|
}
|
|
1393
1492
|
//# sourceMappingURL=api.js.map
|