@juspay/hippocampus 0.1.0 → 0.1.1

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/client.d.ts CHANGED
@@ -1,69 +1,39 @@
1
- import { Engram, EngramCreateInput, EngramUpdateInput, SearchQuery, SearchResult, Chronicle, ChronicleCreateInput, ChronicleUpdateInput, ChronicleQuery, Nexus, NexusCreateInput, HealthResponse, StatusResponse, HippocampusOptions, Strand } from './types';
1
+ import type { HippocampusConfig } from './types';
2
2
  export declare class Hippocampus {
3
- private baseUrl;
4
- private headers;
5
- private retries;
6
- private retryDelay;
7
- constructor(options?: HippocampusOptions);
8
- addMemory(input: EngramCreateInput): Promise<{
9
- engrams: Engram[];
10
- }>;
11
- listEngrams(ownerId: string, options?: {
12
- limit?: number;
13
- offset?: number;
14
- strand?: Strand;
15
- }): Promise<{
16
- engrams: Engram[];
17
- total: number;
18
- }>;
19
- getEngram(id: string): Promise<{
20
- engram: Engram;
21
- }>;
22
- updateEngram(id: string, input: EngramUpdateInput): Promise<{
23
- engram: Engram;
24
- }>;
25
- deleteEngram(id: string): Promise<void>;
26
- search(query: SearchQuery): Promise<SearchResult>;
27
- reinforceEngram(id: string, boost?: number): Promise<{
28
- engram: Engram;
29
- }>;
30
- recordChronicle(input: ChronicleCreateInput): Promise<{
31
- chronicle: Chronicle;
32
- }>;
33
- queryChronicles(query: ChronicleQuery): Promise<{
34
- chronicles: Chronicle[];
35
- total: number;
36
- }>;
37
- getCurrentFact(ownerId: string, entity: string, attribute: string): Promise<{
38
- chronicle: Chronicle;
39
- }>;
40
- getTimeline(ownerId: string, entity: string): Promise<{
41
- chronicles: Chronicle[];
42
- }>;
43
- getChronicle(id: string): Promise<{
44
- chronicle: Chronicle;
45
- }>;
46
- updateChronicle(id: string, input: ChronicleUpdateInput): Promise<{
47
- chronicle: Chronicle;
48
- }>;
49
- expireChronicle(id: string): Promise<void>;
50
- createNexus(input: NexusCreateInput): Promise<{
51
- nexus: Nexus;
52
- }>;
53
- getRelatedChronicles(chronicleId: string): Promise<{
54
- related: {
55
- nexus: Nexus;
56
- chronicle: Chronicle;
57
- }[];
58
- }>;
59
- health(): Promise<HealthResponse>;
60
- status(): Promise<StatusResponse>;
61
- runDecay(ownerId: string): Promise<{
62
- affected: number;
63
- }>;
64
- private request;
65
- private get;
66
- private post;
67
- private patch;
68
- private del;
3
+ private storage;
4
+ private storageConfig;
5
+ private prompt;
6
+ private maxWords;
7
+ private neurolink;
8
+ private config;
9
+ constructor(config?: HippocampusConfig);
10
+ private ensureStorage;
11
+ private ensureNeurolink;
12
+ /**
13
+ * Add/update memory for an owner.
14
+ *
15
+ * Fetches existing memory, merges with new content via LLM, stores result.
16
+ *
17
+ * @param ownerId - Unique identifier (user ID, session ID, etc.)
18
+ * @param content - New conversation content to incorporate
19
+ * @returns The condensed memory string that was stored, or empty string on failure
20
+ */
21
+ add(ownerId: string, content: string): Promise<string>;
22
+ /**
23
+ * Get the stored memory for an owner.
24
+ *
25
+ * @param ownerId - Unique identifier
26
+ * @returns The condensed memory string, or null if none exists or on failure
27
+ */
28
+ get(ownerId: string): Promise<string | null>;
29
+ /**
30
+ * Delete memory for an owner.
31
+ *
32
+ * @param ownerId - Unique identifier
33
+ */
34
+ delete(ownerId: string): Promise<void>;
35
+ /**
36
+ * Close storage connections and clean up resources.
37
+ */
38
+ close(): Promise<void>;
69
39
  }
package/dist/client.js ADDED
@@ -0,0 +1,241 @@
1
+ import { logger } from './logger.js';
2
+
3
+ const DEFAULT_PROMPT = `You are a memory condensation engine. You receive:
4
+ 1. OLD_MEMORY: the user's existing memory summary (may be empty)
5
+ 2. NEW_CONTENT: new conversation content
6
+
7
+ Your job: merge the old memory with relevant new information into a single condensed summary.
8
+
9
+ Rules:
10
+ - Output ONLY the condensed memory text, nothing else
11
+ - Maximum {{MAX_WORDS}} words
12
+ - Preserve important facts: names, preferences, goals, decisions, context
13
+ - Drop greetings, filler, redundant information
14
+ - If NEW_CONTENT has nothing worth remembering, return OLD_MEMORY unchanged
15
+ - If OLD_MEMORY is empty and NEW_CONTENT has nothing worth remembering, return empty string
16
+
17
+ OLD_MEMORY:
18
+ {{OLD_MEMORY}}
19
+
20
+ NEW_CONTENT:
21
+ {{NEW_CONTENT}}
22
+
23
+ Condensed memory:`;
24
+ class Hippocampus {
25
+ storage = null;
26
+ storageConfig;
27
+ prompt;
28
+ maxWords;
29
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
30
+ neurolink = null;
31
+ config;
32
+ constructor(config = {}) {
33
+ this.config = config;
34
+ this.storageConfig = config.storage || { type: 'sqlite' };
35
+ this.prompt = config.prompt || process.env.HC_CONDENSATION_PROMPT || DEFAULT_PROMPT;
36
+ this.maxWords = config.maxWords || 50;
37
+ logger.info('Hippocampus initialized', {
38
+ storage: this.storageConfig.type,
39
+ maxWords: this.maxWords,
40
+ });
41
+ }
42
+ async ensureStorage() {
43
+ if (this.storage) {
44
+ return this.storage;
45
+ }
46
+ try {
47
+ switch (this.storageConfig.type) {
48
+ case 'sqlite': {
49
+ const { SqliteStorage } = await import('./storage/sqlite.js');
50
+ this.storage = new SqliteStorage(this.storageConfig);
51
+ break;
52
+ }
53
+ case 'redis': {
54
+ const { RedisStorage } = await import('./storage/redis.js');
55
+ this.storage = new RedisStorage(this.storageConfig);
56
+ break;
57
+ }
58
+ case 's3': {
59
+ const { S3Storage } = await import('./storage/s3.js');
60
+ this.storage = new S3Storage(this.storageConfig);
61
+ break;
62
+ }
63
+ default:
64
+ logger.error('Unknown storage type', {
65
+ type: this.storageConfig.type,
66
+ });
67
+ return null;
68
+ }
69
+ }
70
+ catch (error) {
71
+ logger.error('Failed to initialize storage backend', {
72
+ type: this.storageConfig.type,
73
+ error: error instanceof Error ? error.message : String(error),
74
+ });
75
+ return null;
76
+ }
77
+ return this.storage;
78
+ }
79
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
80
+ async ensureNeurolink() {
81
+ if (this.neurolink) {
82
+ return this.neurolink;
83
+ }
84
+ try {
85
+ const { NeuroLink } = await import('@juspay/neurolink');
86
+ this.neurolink = new NeuroLink();
87
+ logger.info('NeuroLink instance created for Hippocampus condensation');
88
+ return this.neurolink;
89
+ }
90
+ catch (error) {
91
+ logger.error('Failed to initialize NeuroLink for condensation', {
92
+ error: error instanceof Error ? error.message : String(error),
93
+ });
94
+ return null;
95
+ }
96
+ }
97
+ /**
98
+ * Add/update memory for an owner.
99
+ *
100
+ * Fetches existing memory, merges with new content via LLM, stores result.
101
+ *
102
+ * @param ownerId - Unique identifier (user ID, session ID, etc.)
103
+ * @param content - New conversation content to incorporate
104
+ * @returns The condensed memory string that was stored, or empty string on failure
105
+ */
106
+ async add(ownerId, content) {
107
+ try {
108
+ const storage = await this.ensureStorage();
109
+ if (!storage) {
110
+ return '';
111
+ }
112
+ const neurolink = await this.ensureNeurolink();
113
+ if (!neurolink) {
114
+ return '';
115
+ }
116
+ let oldMemory = '';
117
+ try {
118
+ oldMemory = (await storage.get(ownerId)) || '';
119
+ }
120
+ catch (error) {
121
+ logger.warn('Failed to fetch existing memory, proceeding without it', {
122
+ ownerId,
123
+ error: error instanceof Error ? error.message : String(error),
124
+ });
125
+ }
126
+ const filledPrompt = this.prompt
127
+ .replaceAll('{{OLD_MEMORY}}', oldMemory || '(none)')
128
+ .replaceAll('{{NEW_CONTENT}}', content)
129
+ .replaceAll('{{MAX_WORDS}}', String(this.maxWords));
130
+ logger.debug('Condensing memory', {
131
+ ownerId,
132
+ oldMemoryLength: oldMemory.length,
133
+ newContentLength: content.length,
134
+ });
135
+ let condensed = '';
136
+ try {
137
+ const result = await neurolink.generate({
138
+ input: { text: filledPrompt },
139
+ provider: this.config.neurolink?.provider,
140
+ model: this.config.neurolink?.model,
141
+ temperature: this.config.neurolink?.temperature ?? 0.1,
142
+ disableTools: true,
143
+ });
144
+ condensed = (result?.content || '').trim();
145
+ }
146
+ catch (error) {
147
+ logger.error('LLM condensation call failed', {
148
+ ownerId,
149
+ error: error instanceof Error ? error.message : String(error),
150
+ });
151
+ return oldMemory;
152
+ }
153
+ if (condensed) {
154
+ try {
155
+ await storage.set(ownerId, condensed);
156
+ logger.info('Memory updated', { ownerId, words: condensed.split(/\s+/).length });
157
+ }
158
+ catch (error) {
159
+ logger.error('Failed to persist condensed memory', {
160
+ ownerId,
161
+ error: error instanceof Error ? error.message : String(error),
162
+ });
163
+ }
164
+ }
165
+ else if (oldMemory) {
166
+ logger.debug('No new memory extracted, keeping existing', { ownerId });
167
+ }
168
+ return condensed || oldMemory;
169
+ }
170
+ catch (error) {
171
+ logger.error('Unexpected error in add()', {
172
+ ownerId,
173
+ error: error instanceof Error ? error.message : String(error),
174
+ });
175
+ return '';
176
+ }
177
+ }
178
+ /**
179
+ * Get the stored memory for an owner.
180
+ *
181
+ * @param ownerId - Unique identifier
182
+ * @returns The condensed memory string, or null if none exists or on failure
183
+ */
184
+ async get(ownerId) {
185
+ try {
186
+ const storage = await this.ensureStorage();
187
+ if (!storage) {
188
+ return null;
189
+ }
190
+ return await storage.get(ownerId);
191
+ }
192
+ catch (error) {
193
+ logger.error('Failed to get memory', {
194
+ ownerId,
195
+ error: error instanceof Error ? error.message : String(error),
196
+ });
197
+ return null;
198
+ }
199
+ }
200
+ /**
201
+ * Delete memory for an owner.
202
+ *
203
+ * @param ownerId - Unique identifier
204
+ */
205
+ async delete(ownerId) {
206
+ try {
207
+ const storage = await this.ensureStorage();
208
+ if (!storage) {
209
+ return;
210
+ }
211
+ await storage.delete(ownerId);
212
+ logger.info('Memory deleted', { ownerId });
213
+ }
214
+ catch (error) {
215
+ logger.error('Failed to delete memory', {
216
+ ownerId,
217
+ error: error instanceof Error ? error.message : String(error),
218
+ });
219
+ }
220
+ }
221
+ /**
222
+ * Close storage connections and clean up resources.
223
+ */
224
+ async close() {
225
+ try {
226
+ if (this.storage) {
227
+ await this.storage.close();
228
+ this.storage = null;
229
+ }
230
+ logger.info('Hippocampus closed');
231
+ }
232
+ catch (error) {
233
+ logger.error('Failed to close Hippocampus', {
234
+ error: error instanceof Error ? error.message : String(error),
235
+ });
236
+ this.storage = null;
237
+ }
238
+ }
239
+ }
240
+
241
+ export { Hippocampus };
package/dist/errors.js ADDED
@@ -0,0 +1,19 @@
1
+ class HippocampusError extends Error {
2
+ statusCode;
3
+ details;
4
+ constructor(statusCode, message, details) {
5
+ super(message);
6
+ this.statusCode = statusCode;
7
+ this.details = details;
8
+ this.name = 'HippocampusError';
9
+ }
10
+ static fromResponse(status, body) {
11
+ if (body && typeof body === 'object' && 'error' in body) {
12
+ const err = body.error;
13
+ return new HippocampusError(status, err.message || 'Unknown error', err.details);
14
+ }
15
+ return new HippocampusError(status, `HTTP ${status}`);
16
+ }
17
+ }
18
+
19
+ export { HippocampusError };
package/dist/index.d.ts CHANGED
@@ -2,4 +2,7 @@ export { Hippocampus } from './client';
2
2
  export { HippocampusError } from './errors';
3
3
  export { logger } from './logger';
4
4
  export type { LogLevel } from './logger';
5
- export type { Engram, EngramCreateInput, EngramUpdateInput, SearchQuery, SearchResult, SearchHit, RetrievalTrace, ChronicleHit, Chronicle, ChronicleCreateInput, ChronicleUpdateInput, ChronicleQuery, Nexus, NexusCreateInput, Strand, HealthResponse, StatusResponse, HippocampusOptions, } from './types';
5
+ export type { StorageType, StorageBackend, StorageConfig, SqliteStorageConfig, RedisStorageConfig, S3StorageConfig, HippocampusConfig, } from './types';
6
+ export { SqliteStorage } from './storage/sqlite';
7
+ export { RedisStorage } from './storage/redis';
8
+ export { S3Storage } from './storage/s3';