hippo-memory 1.52.7 → 1.52.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.
Files changed (84) hide show
  1. package/README.md +159 -99
  2. package/dist/api.d.ts +52 -18
  3. package/dist/api.js +155 -86
  4. package/dist/audit.d.ts +2 -1
  5. package/dist/audit.js +63 -0
  6. package/dist/autolearn.js +3 -2
  7. package/dist/capture.d.ts +40 -0
  8. package/dist/capture.js +141 -119
  9. package/dist/churn-git.js +2 -2
  10. package/dist/cli.d.ts +1 -4
  11. package/dist/cli.js +695 -702
  12. package/dist/codex-patch.d.ts +12 -0
  13. package/dist/codex-patch.js +71 -0
  14. package/dist/config.d.ts +0 -1
  15. package/dist/config.js +0 -4
  16. package/dist/connectors/slack/types.d.ts +0 -1
  17. package/dist/consolidate.js +85 -32
  18. package/dist/context-render.d.ts +36 -0
  19. package/dist/context-render.js +154 -0
  20. package/dist/dag.js +3 -2
  21. package/dist/dashboard.js +4 -0
  22. package/dist/db.js +6 -6
  23. package/dist/dedupe.d.ts +6 -6
  24. package/dist/dedupe.js +10 -9
  25. package/dist/doctor.d.ts +1 -1
  26. package/dist/doctor.js +35 -2
  27. package/dist/dormant.d.ts +4 -0
  28. package/dist/dormant.js +17 -2
  29. package/dist/embedding-provider.d.ts +2 -1
  30. package/dist/embedding-provider.js +2 -1
  31. package/dist/embeddings.js +23 -3
  32. package/dist/extensions/openclaw-plugin/index.js +1 -0
  33. package/dist/extract.js +5 -1
  34. package/dist/forward-claim-detector.d.ts +1 -1
  35. package/dist/forward-claim-detector.js +1 -1
  36. package/dist/graph-recall.d.ts +3 -1
  37. package/dist/graph-recall.js +13 -10
  38. package/dist/handoff.d.ts +2 -0
  39. package/dist/hooks.d.ts +19 -5
  40. package/dist/hooks.js +131 -30
  41. package/dist/importers.js +5 -12
  42. package/dist/judgment.d.ts +30 -0
  43. package/dist/judgment.js +122 -0
  44. package/dist/mcp/server.js +174 -213
  45. package/dist/merged-row.d.ts +6 -0
  46. package/dist/merged-row.js +35 -0
  47. package/dist/multihop.d.ts +2 -1
  48. package/dist/multihop.js +7 -4
  49. package/dist/physics-state.d.ts +0 -4
  50. package/dist/physics-state.js +0 -6
  51. package/dist/predictions.d.ts +2 -17
  52. package/dist/predictions.js +2 -15
  53. package/dist/reject-flow.d.ts +7 -5
  54. package/dist/reject-flow.js +41 -12
  55. package/dist/salience.js +12 -5
  56. package/dist/same-text.d.ts +17 -0
  57. package/dist/same-text.js +38 -0
  58. package/dist/scheduler.d.ts +4 -0
  59. package/dist/scheduler.js +8 -0
  60. package/dist/search.d.ts +7 -0
  61. package/dist/search.js +16 -32
  62. package/dist/secret-detect.d.ts +2 -0
  63. package/dist/secret-detect.js +9 -3
  64. package/dist/server-detect.js +9 -33
  65. package/dist/server.js +6 -62
  66. package/dist/session-digest.d.ts +79 -0
  67. package/dist/session-digest.js +528 -0
  68. package/dist/shared.d.ts +11 -3
  69. package/dist/shared.js +41 -31
  70. package/dist/store.d.ts +4 -5
  71. package/dist/store.js +26 -13
  72. package/dist/token-ledger.d.ts +46 -8
  73. package/dist/token-ledger.js +140 -21
  74. package/dist/version.d.ts +1 -1
  75. package/dist/version.js +1 -1
  76. package/dist-ui/assets/index-BhT8RvO6.js +61 -0
  77. package/dist-ui/index.html +1 -1
  78. package/extensions/openclaw-plugin/README.md +4 -4
  79. package/extensions/openclaw-plugin/index.ts +1 -0
  80. package/extensions/openclaw-plugin/openclaw.plugin.json +2 -2
  81. package/extensions/openclaw-plugin/package.json +1 -1
  82. package/openclaw.plugin.json +2 -2
  83. package/package.json +2 -2
  84. package/dist-ui/assets/index-BgmA7Hwe.js +0 -61
package/dist/server.js CHANGED
@@ -2,12 +2,13 @@ import { createServer } from 'node:http';
2
2
  import { createHash } from 'node:crypto';
3
3
  import { dirname, resolve } from 'node:path';
4
4
  import { resolveProjectIdentity } from './project-identity.js';
5
+ import { assembleCost, contextCost, drillCost } from './context-render.js';
5
6
  import { detectServer, writePidfile, removePidfileIfOwned } from './server-detect.js';
6
7
  import { resolveTenantId } from './tenant.js';
7
8
  import { openHippoDb, closeHippoDb } from './db.js';
8
9
  import { updateStats } from './store.js';
9
10
  import { buildSessionKey, getOrCreateRing, appendRecall, snapshotRing, hashQueryText, } from './recall-history.js';
10
- import { appendAuditEvent } from './audit.js';
11
+ import { appendAuditEvent, AUDIT_OPS } from './audit.js';
11
12
  // v0.33 / J1 — Module-level per-(tenant, session) recall-history ring map
12
13
  // for the HTTP pipeline. Separate from CLI/MCP rings per plan v3 (per-
13
14
  // pipeline rings; no IPC). HTTP is the only caller that threads its
@@ -63,65 +64,7 @@ const PUBLIC_ROUTES = new Set([
63
64
  function isPublicRoute(method, path) {
64
65
  return PUBLIC_ROUTES.has(`${method} ${path}`);
65
66
  }
66
- const VALID_AUDIT_OPS = new Set([
67
- 'remember',
68
- 'recall',
69
- 'promote',
70
- 'supersede',
71
- 'forget',
72
- 'archive_raw',
73
- 'auth_revoke',
74
- 'auth_create', // v1.12.4: emitted by api.authCreate
75
- 'outcome', // v1.11.5: pre-existing drift — emitted today but rejected by old Set
76
- 'consolidate', // v1.11.5: emitted by api.sleep / POST /v1/sleep
77
- 'audit_prune', // v1.12.9: emitted by pruneAuditLog
78
- 'summary_marked_dirty', // v0.30 / E1 — lockstep with AuditOp union + cli.ts VALID_AUDIT_OPS (v1.11.5 CRIT A institutional rule)
79
- 'summary_marked_clean', // v0.30 / E3 — buildDag post-link clean op; lockstep
80
- 'summary_rebuilt', // v0.30 / E3 — sleep-cycle rebuild op; lockstep
81
- 'predict_create', // v0.31 / E2 prediction first-class object — emitted by savePrediction
82
- 'predict_close', // v0.31 / E2 — emitted by closePrediction
83
- 'predict_baserate', // v0.31 / J3 — emitted by computePredictionBaserate
84
- 'recall_autodebias_hint', // v0.32 / J3.2 — emitted by computePlanningFallacyHint on success
85
- 'recall_autodebias_hint_no_class_match', // v0.32 / J3.2 — telemetry: forward-claim, no class scored
86
- 'recall_autodebias_hint_tiebreak', // v0.32 / J3.2 — telemetry: forward-claim, >=2 classes tied
87
- 'recall_anchor_detected_query_repeat', // v0.33 / J1 — emitted by detector on R1 fire
88
- 'recall_anchor_detected_memory_dominance', // v0.33 / J1 — emitted by detector on R2 fire
89
- 'recall_anchor_skipped_no_session', // v0.33 / J1 — telemetry: no sessionId, ring skipped
90
- 'recall_availability_detected', // v1.13.x / J2 - emitted when availability/recency-bias hint fires
91
- 'decision_create', // E2 decision first-class object — emitted by saveDecision
92
- 'decision_supersede', // E2 — emitted by saveDecision when --supersedes resolves to an active decision row
93
- 'decision_close', // E2 — emitted by closeDecision
94
- 'incident_open', // E2 incident first-class object — emitted by saveIncident
95
- 'incident_resolve', // E2 — emitted by resolveIncident (open -> resolved)
96
- 'incident_close', // E2 — emitted by closeIncident (open|resolved -> closed)
97
- 'process_create', // E2 process first-class object — emitted by saveProcess
98
- 'process_supersede', // E2 — emitted by saveProcess on a supersession
99
- 'process_close', // E2 — emitted by closeProcess
100
- 'policy_create', // E2 policy first-class object — emitted by savePolicy
101
- 'policy_supersede', // E2 — emitted by savePolicy on a supersession
102
- 'policy_close', // E2 — emitted by closePolicy
103
- 'skill_create', // E2 skill first-class object — emitted by saveSkill
104
- 'skill_supersede', // E2 — emitted by saveSkill on a supersession
105
- 'skill_close', // E2 — emitted by closeSkill
106
- 'project_brief_create', // E2 project_brief first-class object — emitted by saveProjectBrief
107
- 'project_brief_supersede', // E2 — emitted by saveProjectBrief on a supersession (incl. refresh)
108
- 'project_brief_close', // E2 — emitted by closeProjectBrief
109
- 'customer_note_create', // E2 customer_note first-class object — emitted by saveCustomerNote
110
- 'customer_note_supersede', // E2 — emitted by saveCustomerNote on a supersession
111
- 'customer_note_close', // E2 — emitted by closeCustomerNote
112
- 'mv_rescue', // LC2-E3 — emitted by consolidate() per rescue; lockstep with AuditOp union + cli.ts VALID_AUDIT_OPS
113
- 'reject_value', // AT1 — emitted by `hippo reject`; lockstep with AuditOp union + cli.ts VALID_AUDIT_OPS
114
- 'reject_refusal', // AT1 — emitted when the rejection guard refuses a write; lockstep
115
- 'unreject_value', // AT1 — emitted by `hippo unreject`; lockstep
116
- 'conflict_resolve', // AT1 — emitted by resolveConflict on every resolution path; lockstep
117
- 'half_life_migrate', // Decay default change — emitted by migrateDefaultHalfLife; lockstep with AuditOp union
118
- 'dormant_restore', // Dormant memories — emitted by api.restoreDormant; lockstep with AuditOp union + cli.ts VALID_AUDIT_OPS
119
- 'auth_grant', // EI2: emitted by api.authGrant; lockstep with AuditOp union + cli.ts VALID_AUDIT_OPS
120
- 'auth_ungrant', // EI2: emitted by api.authUngrant; lockstep with AuditOp union + cli.ts VALID_AUDIT_OPS
121
- 'quarantine', // CD5: emitted by recordQuarantine; lockstep with AuditOp union + cli.ts VALID_AUDIT_OPS
122
- 'quarantine_approve', // CD5: emitted by api.quarantineApprove; lockstep
123
- 'quarantine_reject', // CD5: emitted by api.quarantineReject; lockstep
124
- ]);
67
+ const VALID_AUDIT_OPS = new Set(AUDIT_OPS);
125
68
  // Cap on GET /v1/audit?limit=. Matches docs/api.md (when written) and is large
126
69
  // enough to dump a small deployment's full audit log without paginating, but
127
70
  // small enough that a malicious client can't ask for the world.
@@ -853,7 +796,7 @@ async function handleRequest(req, res, opts, startedAt, limiter) {
853
796
  assembleExtra.summarizeOlder = summarizeOlder;
854
797
  if (scope !== undefined)
855
798
  assembleExtra.scope = scope;
856
- const result = assemble(ctx, assembleMatch.id, assembleExtra);
799
+ const result = assemble(ctx, assembleMatch.id, { ...assembleExtra, cost: assembleCost(assembleMatch.id) });
857
800
  recordTokens(ctx, 'http_assemble', { items: result.items.length, tokens: result.tokens, sessionId: assembleMatch.id });
858
801
  sendJson(res, 200, result);
859
802
  return;
@@ -896,7 +839,7 @@ async function handleRequest(req, res, opts, startedAt, limiter) {
896
839
  drillExtra.budget = budget;
897
840
  if (depth !== undefined)
898
841
  drillExtra.depth = depth;
899
- const result = drillDown(ctx, drillMatch.id, drillExtra);
842
+ const result = drillDown(ctx, drillMatch.id, { ...drillExtra, cost: drillCost });
900
843
  if ('failure' in result) {
901
844
  // v1.6.4: leaf id maps to 422 (caller-actionable). Other cases stay
902
845
  // as 404 to avoid leaking cross-tenant existence or scope grants.
@@ -1054,6 +997,7 @@ async function handleRequest(req, res, opts, startedAt, limiter) {
1054
997
  includeRecent,
1055
998
  crossProject,
1056
999
  currentProject: resolveProjectIdentity(dirname(resolve(opts.hippoRoot))).name,
1000
+ cost: contextCost('markdown', 'observe'), // clients render; the budget prices the block `hippo context` would print
1057
1001
  });
1058
1002
  recordTokens(ctx, 'http_context', { items: result.entries.length, tokens: result.tokens });
1059
1003
  sendJson(res, 200, result);
@@ -0,0 +1,79 @@
1
+ import { type SessionTurn } from './capture.js';
2
+ import { type MemoryEntry } from './memory.js';
3
+ export declare const SESSION_DIGEST_TAG = "session-digest";
4
+ /** Five-word runs are stock phrases; six in a row is a copied clause. */
5
+ export declare const ECHO_WINDOW = 6;
6
+ /** Five sentences of about 150 chars leave room for the Changed line inside the total cap. */
7
+ export declare const MAX_SENTENCES = 5;
8
+ /** A longer "sentence" in agent text is an unsplit list or pasted output. */
9
+ export declare const MAX_SENTENCE_CHARS = 300;
10
+ /** At about 20 chars per repo path this keeps the Changed line near 50 tokens. */
11
+ export declare const MAX_FILES = 10;
12
+ /** 300 tokens at 4 chars each: 20% of the 1500-token default budget of both context surfaces. */
13
+ export declare const MAX_DIGEST_CHARS = 1200;
14
+ /** Bounds a detached worker's memory; the final message sits at the end, so a tail read loses nothing. */
15
+ export declare const READ_CAP_BYTES: number;
16
+ export interface DigestEdit {
17
+ filePath: string;
18
+ /** Working directory in effect at the call, for relative paths. */
19
+ base: string | null;
20
+ }
21
+ export interface SessionScan {
22
+ turns: SessionTurn[];
23
+ finalText: string;
24
+ /** The first working directory the transcript names: where the session ran. */
25
+ cwd: string | null;
26
+ /** Edits that landed, in call order. */
27
+ edits: DigestEdit[];
28
+ }
29
+ /** One pass over a Claude Code or Codex transcript: the turns capture reads, the closing message, and the edits that landed. */
30
+ export declare function scanSessionTranscript(jsonl: string): SessionScan;
31
+ export declare function readSessionTranscript(transcriptPath: string, log: (message: string) => void): string;
32
+ /** The transcript, read once and scanned, or null with the reason logged. */
33
+ export declare function readSessionScan(transcriptPath: string, log: (message: string) => void): SessionScan | null;
34
+ /** Test-only seam, the scheduler's pattern: lets a test prove a network path never reaches the probe. Null restores it. */
35
+ export declare function __setDigestExistsProbe(probe: ((p: string) => boolean) | null): void;
36
+ /** The store root is realpath'd; transcript paths are not, and a deleted file has no realpath of its own. Null for a network path. */
37
+ export declare function realFsPath(p: string): string | null;
38
+ /** Repo-relative with forward slashes, '' for the root itself, null outside the repo or when the path cannot be resolved. */
39
+ export declare function repoRelative(p: string, repoRoot: string): string | null;
40
+ export declare const USER_SEGMENT: readonly RegExp[];
41
+ /** Sentences of the reply; code spans and "e.g." are held out of the split so their dots never end a sentence. */
42
+ export declare function digestSentences(text: string): string[];
43
+ export declare function sentenceScore(sentence: string): number;
44
+ export interface DigestSources {
45
+ finalText: string;
46
+ /** Text the session already holds: its own prompts, and what hippo injected into it. */
47
+ echoTexts: readonly string[];
48
+ edits: readonly DigestEdit[];
49
+ repoRoot: string;
50
+ }
51
+ export interface DigestDraft {
52
+ content: string;
53
+ sentences: number;
54
+ files: number;
55
+ }
56
+ /** The digest text, or null when nothing survives the filters. Sentences print in reply order. */
57
+ export declare function buildSessionDigest(sources: DigestSources): DigestDraft | null;
58
+ /** Facts extracted from a digest and DAG summaries over one inherit its tag, but they are not the digest itself. */
59
+ export declare function isSessionDigestRow(entry: Pick<MemoryEntry, 'source' | 'tags' | 'extracted_from'>): boolean;
60
+ /** Same session, same row: a second worker for one session updates the digest instead of adding one. */
61
+ export declare function sessionDigestId(tenantId: string, key: string): string;
62
+ export interface SessionDigestOptions {
63
+ /** Session id, or the transcript's basename when the host gives none. */
64
+ key: string;
65
+ tenantId: string;
66
+ }
67
+ export interface DigestOutcome {
68
+ written: boolean;
69
+ reason: string;
70
+ sentences: number;
71
+ files: number;
72
+ }
73
+ export declare function writeSessionDigest(hippoRoot: string, scan: SessionScan, opts: SessionDigestOptions): DigestOutcome;
74
+ export interface DigestRunOptions extends SessionDigestOptions {
75
+ log: (message: string) => void;
76
+ }
77
+ /** Never throws: a digest failure must not block the handoff or the snapshot close. Logs carry no digest text. */
78
+ export declare function recordSessionDigest(hippoRoot: string, scan: SessionScan | null, opts: DigestRunOptions): void;
79
+ //# sourceMappingURL=session-digest.d.ts.map