remembra 0.7.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/README.md +179 -0
- package/dist/index.d.mts +295 -0
- package/dist/index.d.ts +295 -0
- package/dist/index.js +375 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +340 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +57 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remembra TypeScript SDK Types
|
|
3
|
+
*/
|
|
4
|
+
interface RemembraConfig {
|
|
5
|
+
/** Remembra server URL */
|
|
6
|
+
url?: string;
|
|
7
|
+
/** API key for authentication */
|
|
8
|
+
apiKey?: string;
|
|
9
|
+
/** User ID for memory operations */
|
|
10
|
+
userId: string;
|
|
11
|
+
/** Project namespace */
|
|
12
|
+
project?: string;
|
|
13
|
+
/** Request timeout in milliseconds */
|
|
14
|
+
timeout?: number;
|
|
15
|
+
/** Enable debug logging */
|
|
16
|
+
debug?: boolean;
|
|
17
|
+
}
|
|
18
|
+
interface EntityRef {
|
|
19
|
+
id: string;
|
|
20
|
+
canonical_name: string;
|
|
21
|
+
type: string;
|
|
22
|
+
confidence: number;
|
|
23
|
+
}
|
|
24
|
+
interface Memory {
|
|
25
|
+
id: string;
|
|
26
|
+
content: string;
|
|
27
|
+
relevance: number;
|
|
28
|
+
created_at: string;
|
|
29
|
+
metadata?: Record<string, unknown>;
|
|
30
|
+
}
|
|
31
|
+
interface StoreOptions {
|
|
32
|
+
/** Optional key-value metadata */
|
|
33
|
+
metadata?: Record<string, unknown>;
|
|
34
|
+
/** Time-to-live (e.g., "30d", "1y") */
|
|
35
|
+
ttl?: string;
|
|
36
|
+
}
|
|
37
|
+
interface StoreResult {
|
|
38
|
+
id: string;
|
|
39
|
+
extracted_facts: string[];
|
|
40
|
+
entities: EntityRef[];
|
|
41
|
+
}
|
|
42
|
+
interface RecallOptions {
|
|
43
|
+
/** Maximum results (1-50) */
|
|
44
|
+
limit?: number;
|
|
45
|
+
/** Minimum relevance threshold (0.0-1.0) */
|
|
46
|
+
threshold?: number;
|
|
47
|
+
/** Maximum tokens in context */
|
|
48
|
+
maxTokens?: number;
|
|
49
|
+
/** Enable hybrid search */
|
|
50
|
+
enableHybrid?: boolean;
|
|
51
|
+
/** Enable reranking */
|
|
52
|
+
enableRerank?: boolean;
|
|
53
|
+
}
|
|
54
|
+
interface RecallResult {
|
|
55
|
+
context: string;
|
|
56
|
+
memories: Memory[];
|
|
57
|
+
entities: EntityRef[];
|
|
58
|
+
}
|
|
59
|
+
interface ForgetOptions {
|
|
60
|
+
/** Delete specific memory by ID */
|
|
61
|
+
memoryId?: string;
|
|
62
|
+
/** Delete all memories about an entity */
|
|
63
|
+
entity?: string;
|
|
64
|
+
}
|
|
65
|
+
interface ForgetResult {
|
|
66
|
+
deleted_memories: number;
|
|
67
|
+
deleted_entities: number;
|
|
68
|
+
deleted_relationships: number;
|
|
69
|
+
}
|
|
70
|
+
interface Message {
|
|
71
|
+
/** Message role: user, assistant, or system */
|
|
72
|
+
role: 'user' | 'assistant' | 'system';
|
|
73
|
+
/** Message content */
|
|
74
|
+
content: string;
|
|
75
|
+
/** Optional speaker name */
|
|
76
|
+
name?: string;
|
|
77
|
+
/** Optional timestamp (ISO format) */
|
|
78
|
+
timestamp?: string;
|
|
79
|
+
/** Optional metadata */
|
|
80
|
+
metadata?: Record<string, unknown>;
|
|
81
|
+
}
|
|
82
|
+
interface IngestOptions {
|
|
83
|
+
/** Session ID for grouping conversations */
|
|
84
|
+
sessionId?: string;
|
|
85
|
+
/** Which messages to extract from */
|
|
86
|
+
extractFrom?: 'user' | 'assistant' | 'both';
|
|
87
|
+
/** Minimum importance threshold (0.0-1.0) */
|
|
88
|
+
minImportance?: number;
|
|
89
|
+
/** Enable deduplication */
|
|
90
|
+
dedupe?: boolean;
|
|
91
|
+
/** Store results (false for dry-run) */
|
|
92
|
+
store?: boolean;
|
|
93
|
+
/** Enable extraction (false to store raw) */
|
|
94
|
+
infer?: boolean;
|
|
95
|
+
}
|
|
96
|
+
interface ExtractedFact {
|
|
97
|
+
content: string;
|
|
98
|
+
confidence: number;
|
|
99
|
+
importance: number;
|
|
100
|
+
source_message_index: number;
|
|
101
|
+
speaker: string | null;
|
|
102
|
+
stored: boolean;
|
|
103
|
+
memory_id: string | null;
|
|
104
|
+
action: 'add' | 'update' | 'delete' | 'noop' | 'skipped';
|
|
105
|
+
action_reason: string | null;
|
|
106
|
+
}
|
|
107
|
+
interface ExtractedEntity {
|
|
108
|
+
name: string;
|
|
109
|
+
type: string;
|
|
110
|
+
relationship: string | null;
|
|
111
|
+
}
|
|
112
|
+
interface IngestStats {
|
|
113
|
+
messages_processed: number;
|
|
114
|
+
facts_extracted: number;
|
|
115
|
+
facts_stored: number;
|
|
116
|
+
facts_updated: number;
|
|
117
|
+
facts_deduped: number;
|
|
118
|
+
facts_skipped: number;
|
|
119
|
+
entities_found: number;
|
|
120
|
+
processing_time_ms: number;
|
|
121
|
+
}
|
|
122
|
+
interface IngestResult {
|
|
123
|
+
status: 'ok' | 'partial' | 'error';
|
|
124
|
+
session_id: string | null;
|
|
125
|
+
facts: ExtractedFact[];
|
|
126
|
+
entities: ExtractedEntity[];
|
|
127
|
+
stats: IngestStats;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Remembra TypeScript Client
|
|
132
|
+
*
|
|
133
|
+
* Main interface for the Remembra AI Memory Layer.
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```typescript
|
|
137
|
+
* import { Remembra } from 'remembra';
|
|
138
|
+
*
|
|
139
|
+
* const memory = new Remembra({
|
|
140
|
+
* url: 'http://localhost:8787',
|
|
141
|
+
* apiKey: 'your-api-key',
|
|
142
|
+
* userId: 'user_123',
|
|
143
|
+
* });
|
|
144
|
+
*
|
|
145
|
+
* // Store a memory
|
|
146
|
+
* const stored = await memory.store('User prefers dark mode');
|
|
147
|
+
*
|
|
148
|
+
* // Recall memories
|
|
149
|
+
* const result = await memory.recall('What are user preferences?');
|
|
150
|
+
* console.log(result.context);
|
|
151
|
+
*
|
|
152
|
+
* // Ingest a conversation
|
|
153
|
+
* const ingestResult = await memory.ingestConversation([
|
|
154
|
+
* { role: 'user', content: 'My name is John' },
|
|
155
|
+
* { role: 'assistant', content: 'Nice to meet you, John!' },
|
|
156
|
+
* ]);
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
|
|
160
|
+
declare class Remembra {
|
|
161
|
+
private readonly url;
|
|
162
|
+
private readonly apiKey?;
|
|
163
|
+
private readonly userId;
|
|
164
|
+
private readonly project;
|
|
165
|
+
private readonly timeout;
|
|
166
|
+
private readonly debug;
|
|
167
|
+
constructor(config: RemembraConfig);
|
|
168
|
+
private log;
|
|
169
|
+
private request;
|
|
170
|
+
private sleep;
|
|
171
|
+
/**
|
|
172
|
+
* Store a new memory.
|
|
173
|
+
*
|
|
174
|
+
* @param content - Text content to memorize
|
|
175
|
+
* @param options - Optional metadata and TTL
|
|
176
|
+
* @returns Stored memory with extracted facts and entities
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```typescript
|
|
180
|
+
* const result = await memory.store('User prefers dark mode', {
|
|
181
|
+
* metadata: { source: 'settings' },
|
|
182
|
+
* ttl: '30d',
|
|
183
|
+
* });
|
|
184
|
+
* console.log(result.extracted_facts);
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
store(content: string, options?: StoreOptions): Promise<StoreResult>;
|
|
188
|
+
/**
|
|
189
|
+
* Recall memories relevant to a query.
|
|
190
|
+
*
|
|
191
|
+
* @param query - Natural language query
|
|
192
|
+
* @param options - Recall options (limit, threshold, etc.)
|
|
193
|
+
* @returns Context string and matching memories
|
|
194
|
+
*
|
|
195
|
+
* @example
|
|
196
|
+
* ```typescript
|
|
197
|
+
* const result = await memory.recall('What are user preferences?');
|
|
198
|
+
* console.log(result.context); // Synthesized context
|
|
199
|
+
* console.log(result.memories); // Individual memories
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
202
|
+
recall(query: string, options?: RecallOptions): Promise<RecallResult>;
|
|
203
|
+
/**
|
|
204
|
+
* Get a specific memory by ID.
|
|
205
|
+
*
|
|
206
|
+
* @param memoryId - Memory ID
|
|
207
|
+
* @returns Memory details
|
|
208
|
+
*/
|
|
209
|
+
get(memoryId: string): Promise<Memory>;
|
|
210
|
+
/**
|
|
211
|
+
* Forget (delete) memories.
|
|
212
|
+
*
|
|
213
|
+
* @param options - What to delete (memoryId, entity, or all)
|
|
214
|
+
* @returns Deletion counts
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* ```typescript
|
|
218
|
+
* // Delete specific memory
|
|
219
|
+
* await memory.forget({ memoryId: 'mem_123' });
|
|
220
|
+
*
|
|
221
|
+
* // Delete all about an entity
|
|
222
|
+
* await memory.forget({ entity: 'John' });
|
|
223
|
+
* ```
|
|
224
|
+
*/
|
|
225
|
+
forget(options?: ForgetOptions): Promise<ForgetResult>;
|
|
226
|
+
/**
|
|
227
|
+
* Ingest a conversation and automatically extract memories.
|
|
228
|
+
*
|
|
229
|
+
* This is the primary method for AI agents to add conversation context
|
|
230
|
+
* to persistent memory without manually calling store for each fact.
|
|
231
|
+
*
|
|
232
|
+
* @param messages - Array of conversation messages
|
|
233
|
+
* @param options - Ingestion options
|
|
234
|
+
* @returns Extracted facts, entities, and stats
|
|
235
|
+
*
|
|
236
|
+
* @example
|
|
237
|
+
* ```typescript
|
|
238
|
+
* const result = await memory.ingestConversation([
|
|
239
|
+
* { role: 'user', content: 'My name is John and I work at Google' },
|
|
240
|
+
* { role: 'assistant', content: 'Nice to meet you, John!' },
|
|
241
|
+
* ], {
|
|
242
|
+
* minImportance: 0.5,
|
|
243
|
+
* });
|
|
244
|
+
*
|
|
245
|
+
* console.log(`Extracted ${result.stats.facts_extracted} facts`);
|
|
246
|
+
* console.log(`Stored ${result.stats.facts_stored} new memories`);
|
|
247
|
+
* ```
|
|
248
|
+
*/
|
|
249
|
+
ingestConversation(messages: Message[], options?: IngestOptions): Promise<IngestResult>;
|
|
250
|
+
/**
|
|
251
|
+
* Check server health.
|
|
252
|
+
*
|
|
253
|
+
* @returns Health status
|
|
254
|
+
*/
|
|
255
|
+
health(): Promise<Record<string, unknown>>;
|
|
256
|
+
/**
|
|
257
|
+
* List entities for the current user.
|
|
258
|
+
*
|
|
259
|
+
* @returns Array of entities
|
|
260
|
+
*/
|
|
261
|
+
listEntities(): Promise<EntityRef[]>;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Remembra SDK Error Classes
|
|
266
|
+
*/
|
|
267
|
+
declare class RemembraError extends Error {
|
|
268
|
+
readonly status?: number;
|
|
269
|
+
readonly code?: string;
|
|
270
|
+
constructor(message: string, status?: number, code?: string);
|
|
271
|
+
}
|
|
272
|
+
declare class AuthenticationError extends RemembraError {
|
|
273
|
+
constructor(message?: string);
|
|
274
|
+
}
|
|
275
|
+
declare class NotFoundError extends RemembraError {
|
|
276
|
+
constructor(message?: string);
|
|
277
|
+
}
|
|
278
|
+
declare class ValidationError extends RemembraError {
|
|
279
|
+
constructor(message: string);
|
|
280
|
+
}
|
|
281
|
+
declare class RateLimitError extends RemembraError {
|
|
282
|
+
readonly retryAfter?: number;
|
|
283
|
+
constructor(message?: string, retryAfter?: number);
|
|
284
|
+
}
|
|
285
|
+
declare class ServerError extends RemembraError {
|
|
286
|
+
constructor(message?: string);
|
|
287
|
+
}
|
|
288
|
+
declare class NetworkError extends RemembraError {
|
|
289
|
+
constructor(message?: string);
|
|
290
|
+
}
|
|
291
|
+
declare class TimeoutError extends RemembraError {
|
|
292
|
+
constructor(message?: string);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
export { AuthenticationError, type EntityRef, type ExtractedEntity, type ExtractedFact, type ForgetOptions, type ForgetResult, type IngestOptions, type IngestResult, type IngestStats, type Memory, type Message, NetworkError, NotFoundError, RateLimitError, type RecallOptions, type RecallResult, Remembra, type RemembraConfig, RemembraError, ServerError, type StoreOptions, type StoreResult, TimeoutError, ValidationError };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
AuthenticationError: () => AuthenticationError,
|
|
24
|
+
NetworkError: () => NetworkError,
|
|
25
|
+
NotFoundError: () => NotFoundError,
|
|
26
|
+
RateLimitError: () => RateLimitError,
|
|
27
|
+
Remembra: () => Remembra,
|
|
28
|
+
RemembraError: () => RemembraError,
|
|
29
|
+
ServerError: () => ServerError,
|
|
30
|
+
TimeoutError: () => TimeoutError,
|
|
31
|
+
ValidationError: () => ValidationError
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(index_exports);
|
|
34
|
+
|
|
35
|
+
// src/errors.ts
|
|
36
|
+
var RemembraError = class _RemembraError extends Error {
|
|
37
|
+
constructor(message, status, code) {
|
|
38
|
+
super(message);
|
|
39
|
+
this.name = "RemembraError";
|
|
40
|
+
this.status = status;
|
|
41
|
+
this.code = code;
|
|
42
|
+
if (Error.captureStackTrace) {
|
|
43
|
+
Error.captureStackTrace(this, _RemembraError);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
var AuthenticationError = class extends RemembraError {
|
|
48
|
+
constructor(message = "Authentication failed") {
|
|
49
|
+
super(message, 401, "AUTH_ERROR");
|
|
50
|
+
this.name = "AuthenticationError";
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
var NotFoundError = class extends RemembraError {
|
|
54
|
+
constructor(message = "Resource not found") {
|
|
55
|
+
super(message, 404, "NOT_FOUND");
|
|
56
|
+
this.name = "NotFoundError";
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
var ValidationError = class extends RemembraError {
|
|
60
|
+
constructor(message) {
|
|
61
|
+
super(message, 422, "VALIDATION_ERROR");
|
|
62
|
+
this.name = "ValidationError";
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
var RateLimitError = class extends RemembraError {
|
|
66
|
+
constructor(message = "Rate limit exceeded", retryAfter) {
|
|
67
|
+
super(message, 429, "RATE_LIMITED");
|
|
68
|
+
this.name = "RateLimitError";
|
|
69
|
+
this.retryAfter = retryAfter;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
var ServerError = class extends RemembraError {
|
|
73
|
+
constructor(message = "Internal server error") {
|
|
74
|
+
super(message, 500, "SERVER_ERROR");
|
|
75
|
+
this.name = "ServerError";
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
var NetworkError = class extends RemembraError {
|
|
79
|
+
constructor(message = "Network error") {
|
|
80
|
+
super(message, void 0, "NETWORK_ERROR");
|
|
81
|
+
this.name = "NetworkError";
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
var TimeoutError = class extends RemembraError {
|
|
85
|
+
constructor(message = "Request timed out") {
|
|
86
|
+
super(message, void 0, "TIMEOUT");
|
|
87
|
+
this.name = "TimeoutError";
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// src/client.ts
|
|
92
|
+
var DEFAULT_URL = "http://localhost:8787";
|
|
93
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
94
|
+
var MAX_RETRIES = 3;
|
|
95
|
+
var RETRY_DELAY = 1e3;
|
|
96
|
+
var Remembra = class {
|
|
97
|
+
constructor(config) {
|
|
98
|
+
this.url = (config.url || DEFAULT_URL).replace(/\/$/, "");
|
|
99
|
+
this.apiKey = config.apiKey;
|
|
100
|
+
this.userId = config.userId;
|
|
101
|
+
this.project = config.project || "default";
|
|
102
|
+
this.timeout = config.timeout || DEFAULT_TIMEOUT;
|
|
103
|
+
this.debug = config.debug || false;
|
|
104
|
+
if (!this.userId) {
|
|
105
|
+
throw new ValidationError("userId is required");
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// ===========================================================================
|
|
109
|
+
// Private Methods
|
|
110
|
+
// ===========================================================================
|
|
111
|
+
log(...args) {
|
|
112
|
+
if (this.debug) {
|
|
113
|
+
console.log("[Remembra]", ...args);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async request(method, path, options = {}) {
|
|
117
|
+
const { body, params, retries = MAX_RETRIES } = options;
|
|
118
|
+
const url = new URL(`${this.url}${path}`);
|
|
119
|
+
if (params) {
|
|
120
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
121
|
+
if (value !== void 0) {
|
|
122
|
+
url.searchParams.set(key, value);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
const headers = {
|
|
127
|
+
"Content-Type": "application/json",
|
|
128
|
+
"User-Agent": "remembra-js/0.1.0"
|
|
129
|
+
};
|
|
130
|
+
if (this.apiKey) {
|
|
131
|
+
headers["X-API-Key"] = this.apiKey;
|
|
132
|
+
}
|
|
133
|
+
this.log(method, path, body ? JSON.stringify(body).slice(0, 100) : "");
|
|
134
|
+
let lastError;
|
|
135
|
+
for (let attempt = 0; attempt < retries; attempt++) {
|
|
136
|
+
try {
|
|
137
|
+
const controller = new AbortController();
|
|
138
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
139
|
+
const response = await fetch(url.toString(), {
|
|
140
|
+
method,
|
|
141
|
+
headers,
|
|
142
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
143
|
+
signal: controller.signal
|
|
144
|
+
});
|
|
145
|
+
clearTimeout(timeoutId);
|
|
146
|
+
if (response.ok) {
|
|
147
|
+
return await response.json();
|
|
148
|
+
}
|
|
149
|
+
const errorBody = await response.json().catch(() => ({}));
|
|
150
|
+
const errorMessage = errorBody.detail || response.statusText;
|
|
151
|
+
switch (response.status) {
|
|
152
|
+
case 401:
|
|
153
|
+
throw new AuthenticationError(errorMessage);
|
|
154
|
+
case 404:
|
|
155
|
+
throw new NotFoundError(errorMessage);
|
|
156
|
+
case 422:
|
|
157
|
+
throw new ValidationError(errorMessage);
|
|
158
|
+
case 429:
|
|
159
|
+
const retryAfter = parseInt(response.headers.get("Retry-After") || "60", 10);
|
|
160
|
+
if (attempt < retries - 1) {
|
|
161
|
+
this.log(`Rate limited, retrying in ${retryAfter}s...`);
|
|
162
|
+
await this.sleep(retryAfter * 1e3);
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
throw new RateLimitError(errorMessage, retryAfter);
|
|
166
|
+
case 500:
|
|
167
|
+
case 502:
|
|
168
|
+
case 503:
|
|
169
|
+
case 504:
|
|
170
|
+
if (attempt < retries - 1) {
|
|
171
|
+
this.log(`Server error (${response.status}), retrying...`);
|
|
172
|
+
await this.sleep(RETRY_DELAY * Math.pow(2, attempt));
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
throw new ServerError(errorMessage);
|
|
176
|
+
default:
|
|
177
|
+
throw new RemembraError(errorMessage, response.status);
|
|
178
|
+
}
|
|
179
|
+
} catch (error) {
|
|
180
|
+
lastError = error;
|
|
181
|
+
if (error instanceof RemembraError) {
|
|
182
|
+
throw error;
|
|
183
|
+
}
|
|
184
|
+
if (error instanceof Error) {
|
|
185
|
+
if (error.name === "AbortError") {
|
|
186
|
+
throw new TimeoutError(`Request timed out after ${this.timeout}ms`);
|
|
187
|
+
}
|
|
188
|
+
if (attempt < retries - 1) {
|
|
189
|
+
this.log(`Network error, retrying...`, error.message);
|
|
190
|
+
await this.sleep(RETRY_DELAY * Math.pow(2, attempt));
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
throw new NetworkError(error.message);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
throw lastError || new NetworkError("Request failed");
|
|
198
|
+
}
|
|
199
|
+
sleep(ms) {
|
|
200
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
201
|
+
}
|
|
202
|
+
// ===========================================================================
|
|
203
|
+
// Core Operations
|
|
204
|
+
// ===========================================================================
|
|
205
|
+
/**
|
|
206
|
+
* Store a new memory.
|
|
207
|
+
*
|
|
208
|
+
* @param content - Text content to memorize
|
|
209
|
+
* @param options - Optional metadata and TTL
|
|
210
|
+
* @returns Stored memory with extracted facts and entities
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* ```typescript
|
|
214
|
+
* const result = await memory.store('User prefers dark mode', {
|
|
215
|
+
* metadata: { source: 'settings' },
|
|
216
|
+
* ttl: '30d',
|
|
217
|
+
* });
|
|
218
|
+
* console.log(result.extracted_facts);
|
|
219
|
+
* ```
|
|
220
|
+
*/
|
|
221
|
+
async store(content, options = {}) {
|
|
222
|
+
return this.request("POST", "/api/v1/memories", {
|
|
223
|
+
body: {
|
|
224
|
+
user_id: this.userId,
|
|
225
|
+
project_id: this.project,
|
|
226
|
+
content,
|
|
227
|
+
metadata: options.metadata || {},
|
|
228
|
+
ttl: options.ttl
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Recall memories relevant to a query.
|
|
234
|
+
*
|
|
235
|
+
* @param query - Natural language query
|
|
236
|
+
* @param options - Recall options (limit, threshold, etc.)
|
|
237
|
+
* @returns Context string and matching memories
|
|
238
|
+
*
|
|
239
|
+
* @example
|
|
240
|
+
* ```typescript
|
|
241
|
+
* const result = await memory.recall('What are user preferences?');
|
|
242
|
+
* console.log(result.context); // Synthesized context
|
|
243
|
+
* console.log(result.memories); // Individual memories
|
|
244
|
+
* ```
|
|
245
|
+
*/
|
|
246
|
+
async recall(query, options = {}) {
|
|
247
|
+
return this.request("POST", "/api/v1/memories/recall", {
|
|
248
|
+
body: {
|
|
249
|
+
user_id: this.userId,
|
|
250
|
+
project_id: this.project,
|
|
251
|
+
query,
|
|
252
|
+
limit: options.limit || 5,
|
|
253
|
+
threshold: options.threshold || 0.4,
|
|
254
|
+
max_tokens: options.maxTokens,
|
|
255
|
+
enable_hybrid: options.enableHybrid,
|
|
256
|
+
enable_rerank: options.enableRerank
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Get a specific memory by ID.
|
|
262
|
+
*
|
|
263
|
+
* @param memoryId - Memory ID
|
|
264
|
+
* @returns Memory details
|
|
265
|
+
*/
|
|
266
|
+
async get(memoryId) {
|
|
267
|
+
return this.request("GET", `/api/v1/memories/${memoryId}`);
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Forget (delete) memories.
|
|
271
|
+
*
|
|
272
|
+
* @param options - What to delete (memoryId, entity, or all)
|
|
273
|
+
* @returns Deletion counts
|
|
274
|
+
*
|
|
275
|
+
* @example
|
|
276
|
+
* ```typescript
|
|
277
|
+
* // Delete specific memory
|
|
278
|
+
* await memory.forget({ memoryId: 'mem_123' });
|
|
279
|
+
*
|
|
280
|
+
* // Delete all about an entity
|
|
281
|
+
* await memory.forget({ entity: 'John' });
|
|
282
|
+
* ```
|
|
283
|
+
*/
|
|
284
|
+
async forget(options = {}) {
|
|
285
|
+
const params = {};
|
|
286
|
+
if (options.memoryId) {
|
|
287
|
+
params.memory_id = options.memoryId;
|
|
288
|
+
} else if (options.entity) {
|
|
289
|
+
params.entity = options.entity;
|
|
290
|
+
} else {
|
|
291
|
+
params.user_id = this.userId;
|
|
292
|
+
}
|
|
293
|
+
return this.request("DELETE", "/api/v1/memories", { params });
|
|
294
|
+
}
|
|
295
|
+
// ===========================================================================
|
|
296
|
+
// Conversation Ingestion
|
|
297
|
+
// ===========================================================================
|
|
298
|
+
/**
|
|
299
|
+
* Ingest a conversation and automatically extract memories.
|
|
300
|
+
*
|
|
301
|
+
* This is the primary method for AI agents to add conversation context
|
|
302
|
+
* to persistent memory without manually calling store for each fact.
|
|
303
|
+
*
|
|
304
|
+
* @param messages - Array of conversation messages
|
|
305
|
+
* @param options - Ingestion options
|
|
306
|
+
* @returns Extracted facts, entities, and stats
|
|
307
|
+
*
|
|
308
|
+
* @example
|
|
309
|
+
* ```typescript
|
|
310
|
+
* const result = await memory.ingestConversation([
|
|
311
|
+
* { role: 'user', content: 'My name is John and I work at Google' },
|
|
312
|
+
* { role: 'assistant', content: 'Nice to meet you, John!' },
|
|
313
|
+
* ], {
|
|
314
|
+
* minImportance: 0.5,
|
|
315
|
+
* });
|
|
316
|
+
*
|
|
317
|
+
* console.log(`Extracted ${result.stats.facts_extracted} facts`);
|
|
318
|
+
* console.log(`Stored ${result.stats.facts_stored} new memories`);
|
|
319
|
+
* ```
|
|
320
|
+
*/
|
|
321
|
+
async ingestConversation(messages, options = {}) {
|
|
322
|
+
return this.request("POST", "/api/v1/ingest/conversation", {
|
|
323
|
+
body: {
|
|
324
|
+
messages,
|
|
325
|
+
user_id: this.userId,
|
|
326
|
+
project_id: this.project,
|
|
327
|
+
session_id: options.sessionId,
|
|
328
|
+
options: {
|
|
329
|
+
extract_from: options.extractFrom || "both",
|
|
330
|
+
min_importance: options.minImportance ?? 0.5,
|
|
331
|
+
dedupe: options.dedupe ?? true,
|
|
332
|
+
store: options.store ?? true,
|
|
333
|
+
infer: options.infer ?? true
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
// ===========================================================================
|
|
339
|
+
// Utilities
|
|
340
|
+
// ===========================================================================
|
|
341
|
+
/**
|
|
342
|
+
* Check server health.
|
|
343
|
+
*
|
|
344
|
+
* @returns Health status
|
|
345
|
+
*/
|
|
346
|
+
async health() {
|
|
347
|
+
return this.request("GET", "/health");
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* List entities for the current user.
|
|
351
|
+
*
|
|
352
|
+
* @returns Array of entities
|
|
353
|
+
*/
|
|
354
|
+
async listEntities() {
|
|
355
|
+
const result = await this.request(
|
|
356
|
+
"GET",
|
|
357
|
+
"/api/v1/entities",
|
|
358
|
+
{ params: { user_id: this.userId, project_id: this.project } }
|
|
359
|
+
);
|
|
360
|
+
return result.entities || [];
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
364
|
+
0 && (module.exports = {
|
|
365
|
+
AuthenticationError,
|
|
366
|
+
NetworkError,
|
|
367
|
+
NotFoundError,
|
|
368
|
+
RateLimitError,
|
|
369
|
+
Remembra,
|
|
370
|
+
RemembraError,
|
|
371
|
+
ServerError,
|
|
372
|
+
TimeoutError,
|
|
373
|
+
ValidationError
|
|
374
|
+
});
|
|
375
|
+
//# sourceMappingURL=index.js.map
|