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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/client.ts"],"sourcesContent":["/**\n * Remembra - AI Memory Layer SDK\n * \n * @packageDocumentation\n * \n * @example\n * ```typescript\n * import { Remembra } from 'remembra';\n * \n * const memory = new Remembra({\n * url: 'http://localhost:8787',\n * apiKey: 'your-api-key',\n * userId: 'user_123',\n * });\n * \n * // Store memories\n * await memory.store('User prefers dark mode');\n * \n * // Recall memories\n * const result = await memory.recall('preferences');\n * console.log(result.context);\n * \n * // Ingest conversations\n * await memory.ingestConversation([\n * { role: 'user', content: 'My name is John' },\n * ]);\n * ```\n */\n\n// Main client\nexport { Remembra } from './client';\n\n// Types\nexport type {\n RemembraConfig,\n StoreOptions,\n StoreResult,\n RecallOptions,\n RecallResult,\n ForgetOptions,\n ForgetResult,\n Message,\n IngestOptions,\n IngestResult,\n ExtractedFact,\n ExtractedEntity,\n IngestStats,\n Memory,\n EntityRef,\n} from './types';\n\n// Errors\nexport {\n RemembraError,\n AuthenticationError,\n NotFoundError,\n ValidationError,\n RateLimitError,\n ServerError,\n NetworkError,\n TimeoutError,\n} from './errors';\n","/**\n * Remembra SDK Error Classes\n */\n\nexport class RemembraError extends Error {\n public readonly status?: number;\n public readonly code?: string;\n\n constructor(message: string, status?: number, code?: string) {\n super(message);\n this.name = 'RemembraError';\n this.status = status;\n this.code = code;\n \n // Maintain proper stack trace in V8\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, RemembraError);\n }\n }\n}\n\nexport class AuthenticationError extends RemembraError {\n constructor(message = 'Authentication failed') {\n super(message, 401, 'AUTH_ERROR');\n this.name = 'AuthenticationError';\n }\n}\n\nexport class NotFoundError extends RemembraError {\n constructor(message = 'Resource not found') {\n super(message, 404, 'NOT_FOUND');\n this.name = 'NotFoundError';\n }\n}\n\nexport class ValidationError extends RemembraError {\n constructor(message: string) {\n super(message, 422, 'VALIDATION_ERROR');\n this.name = 'ValidationError';\n }\n}\n\nexport class RateLimitError extends RemembraError {\n public readonly retryAfter?: number;\n\n constructor(message = 'Rate limit exceeded', retryAfter?: number) {\n super(message, 429, 'RATE_LIMITED');\n this.name = 'RateLimitError';\n this.retryAfter = retryAfter;\n }\n}\n\nexport class ServerError extends RemembraError {\n constructor(message = 'Internal server error') {\n super(message, 500, 'SERVER_ERROR');\n this.name = 'ServerError';\n }\n}\n\nexport class NetworkError extends RemembraError {\n constructor(message = 'Network error') {\n super(message, undefined, 'NETWORK_ERROR');\n this.name = 'NetworkError';\n }\n}\n\nexport class TimeoutError extends RemembraError {\n constructor(message = 'Request timed out') {\n super(message, undefined, 'TIMEOUT');\n this.name = 'TimeoutError';\n }\n}\n","/**\n * Remembra TypeScript Client\n * \n * Main interface for the Remembra AI Memory Layer.\n * \n * @example\n * ```typescript\n * import { Remembra } from 'remembra';\n * \n * const memory = new Remembra({\n * url: 'http://localhost:8787',\n * apiKey: 'your-api-key',\n * userId: 'user_123',\n * });\n * \n * // Store a memory\n * const stored = await memory.store('User prefers dark mode');\n * \n * // Recall memories\n * const result = await memory.recall('What are user preferences?');\n * console.log(result.context);\n * \n * // Ingest a conversation\n * const ingestResult = await memory.ingestConversation([\n * { role: 'user', content: 'My name is John' },\n * { role: 'assistant', content: 'Nice to meet you, John!' },\n * ]);\n * ```\n */\n\nimport type {\n RemembraConfig,\n StoreOptions,\n StoreResult,\n RecallOptions,\n RecallResult,\n ForgetOptions,\n ForgetResult,\n Message,\n IngestOptions,\n IngestResult,\n Memory,\n EntityRef,\n} from './types';\n\nimport {\n RemembraError,\n AuthenticationError,\n NotFoundError,\n ValidationError,\n RateLimitError,\n ServerError,\n NetworkError,\n TimeoutError,\n} from './errors';\n\nconst DEFAULT_URL = 'http://localhost:8787';\nconst DEFAULT_TIMEOUT = 30000;\nconst MAX_RETRIES = 3;\nconst RETRY_DELAY = 1000;\n\nexport class Remembra {\n private readonly url: string;\n private readonly apiKey?: string;\n private readonly userId: string;\n private readonly project: string;\n private readonly timeout: number;\n private readonly debug: boolean;\n\n constructor(config: RemembraConfig) {\n this.url = (config.url || DEFAULT_URL).replace(/\\/$/, '');\n this.apiKey = config.apiKey;\n this.userId = config.userId;\n this.project = config.project || 'default';\n this.timeout = config.timeout || DEFAULT_TIMEOUT;\n this.debug = config.debug || false;\n\n if (!this.userId) {\n throw new ValidationError('userId is required');\n }\n }\n\n // ===========================================================================\n // Private Methods\n // ===========================================================================\n\n private log(...args: unknown[]): void {\n if (this.debug) {\n console.log('[Remembra]', ...args);\n }\n }\n\n private async request<T>(\n method: string,\n path: string,\n options: {\n body?: unknown;\n params?: Record<string, string>;\n retries?: number;\n } = {}\n ): Promise<T> {\n const { body, params, retries = MAX_RETRIES } = options;\n\n // Build URL with query params\n const url = new URL(`${this.url}${path}`);\n if (params) {\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined) {\n url.searchParams.set(key, value);\n }\n });\n }\n\n // Build headers\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'User-Agent': 'remembra-js/0.1.0',\n };\n if (this.apiKey) {\n headers['X-API-Key'] = this.apiKey;\n }\n\n this.log(method, path, body ? JSON.stringify(body).slice(0, 100) : '');\n\n // Execute with retry\n let lastError: Error | undefined;\n \n for (let attempt = 0; attempt < retries; attempt++) {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n const response = await fetch(url.toString(), {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n // Handle response\n if (response.ok) {\n return await response.json() as T;\n }\n\n // Handle errors\n const errorBody = await response.json().catch(() => ({})) as { detail?: string };\n const errorMessage = errorBody.detail || response.statusText;\n\n switch (response.status) {\n case 401:\n throw new AuthenticationError(errorMessage);\n case 404:\n throw new NotFoundError(errorMessage);\n case 422:\n throw new ValidationError(errorMessage);\n case 429:\n const retryAfter = parseInt(response.headers.get('Retry-After') || '60', 10);\n if (attempt < retries - 1) {\n this.log(`Rate limited, retrying in ${retryAfter}s...`);\n await this.sleep(retryAfter * 1000);\n continue;\n }\n throw new RateLimitError(errorMessage, retryAfter);\n case 500:\n case 502:\n case 503:\n case 504:\n if (attempt < retries - 1) {\n this.log(`Server error (${response.status}), retrying...`);\n await this.sleep(RETRY_DELAY * Math.pow(2, attempt));\n continue;\n }\n throw new ServerError(errorMessage);\n default:\n throw new RemembraError(errorMessage, response.status);\n }\n } catch (error) {\n lastError = error as Error;\n\n if (error instanceof RemembraError) {\n throw error;\n }\n\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n throw new TimeoutError(`Request timed out after ${this.timeout}ms`);\n }\n if (attempt < retries - 1) {\n this.log(`Network error, retrying...`, error.message);\n await this.sleep(RETRY_DELAY * Math.pow(2, attempt));\n continue;\n }\n throw new NetworkError(error.message);\n }\n }\n }\n\n throw lastError || new NetworkError('Request failed');\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n // ===========================================================================\n // Core Operations\n // ===========================================================================\n\n /**\n * Store a new memory.\n * \n * @param content - Text content to memorize\n * @param options - Optional metadata and TTL\n * @returns Stored memory with extracted facts and entities\n * \n * @example\n * ```typescript\n * const result = await memory.store('User prefers dark mode', {\n * metadata: { source: 'settings' },\n * ttl: '30d',\n * });\n * console.log(result.extracted_facts);\n * ```\n */\n async store(content: string, options: StoreOptions = {}): Promise<StoreResult> {\n return this.request<StoreResult>('POST', '/api/v1/memories', {\n body: {\n user_id: this.userId,\n project_id: this.project,\n content,\n metadata: options.metadata || {},\n ttl: options.ttl,\n },\n });\n }\n\n /**\n * Recall memories relevant to a query.\n * \n * @param query - Natural language query\n * @param options - Recall options (limit, threshold, etc.)\n * @returns Context string and matching memories\n * \n * @example\n * ```typescript\n * const result = await memory.recall('What are user preferences?');\n * console.log(result.context); // Synthesized context\n * console.log(result.memories); // Individual memories\n * ```\n */\n async recall(query: string, options: RecallOptions = {}): Promise<RecallResult> {\n return this.request<RecallResult>('POST', '/api/v1/memories/recall', {\n body: {\n user_id: this.userId,\n project_id: this.project,\n query,\n limit: options.limit || 5,\n threshold: options.threshold || 0.4,\n max_tokens: options.maxTokens,\n enable_hybrid: options.enableHybrid,\n enable_rerank: options.enableRerank,\n },\n });\n }\n\n /**\n * Get a specific memory by ID.\n * \n * @param memoryId - Memory ID\n * @returns Memory details\n */\n async get(memoryId: string): Promise<Memory> {\n return this.request<Memory>('GET', `/api/v1/memories/${memoryId}`);\n }\n\n /**\n * Forget (delete) memories.\n * \n * @param options - What to delete (memoryId, entity, or all)\n * @returns Deletion counts\n * \n * @example\n * ```typescript\n * // Delete specific memory\n * await memory.forget({ memoryId: 'mem_123' });\n * \n * // Delete all about an entity\n * await memory.forget({ entity: 'John' });\n * ```\n */\n async forget(options: ForgetOptions = {}): Promise<ForgetResult> {\n const params: Record<string, string> = {};\n \n if (options.memoryId) {\n params.memory_id = options.memoryId;\n } else if (options.entity) {\n params.entity = options.entity;\n } else {\n params.user_id = this.userId;\n }\n\n return this.request<ForgetResult>('DELETE', '/api/v1/memories', { params });\n }\n\n // ===========================================================================\n // Conversation Ingestion\n // ===========================================================================\n\n /**\n * Ingest a conversation and automatically extract memories.\n * \n * This is the primary method for AI agents to add conversation context\n * to persistent memory without manually calling store for each fact.\n * \n * @param messages - Array of conversation messages\n * @param options - Ingestion options\n * @returns Extracted facts, entities, and stats\n * \n * @example\n * ```typescript\n * const result = await memory.ingestConversation([\n * { role: 'user', content: 'My name is John and I work at Google' },\n * { role: 'assistant', content: 'Nice to meet you, John!' },\n * ], {\n * minImportance: 0.5,\n * });\n * \n * console.log(`Extracted ${result.stats.facts_extracted} facts`);\n * console.log(`Stored ${result.stats.facts_stored} new memories`);\n * ```\n */\n async ingestConversation(\n messages: Message[],\n options: IngestOptions = {}\n ): Promise<IngestResult> {\n return this.request<IngestResult>('POST', '/api/v1/ingest/conversation', {\n body: {\n messages,\n user_id: this.userId,\n project_id: this.project,\n session_id: options.sessionId,\n options: {\n extract_from: options.extractFrom || 'both',\n min_importance: options.minImportance ?? 0.5,\n dedupe: options.dedupe ?? true,\n store: options.store ?? true,\n infer: options.infer ?? true,\n },\n },\n });\n }\n\n // ===========================================================================\n // Utilities\n // ===========================================================================\n\n /**\n * Check server health.\n * \n * @returns Health status\n */\n async health(): Promise<Record<string, unknown>> {\n return this.request<Record<string, unknown>>('GET', '/health');\n }\n\n /**\n * List entities for the current user.\n * \n * @returns Array of entities\n */\n async listEntities(): Promise<EntityRef[]> {\n const result = await this.request<{ entities: EntityRef[] }>(\n 'GET',\n '/api/v1/entities',\n { params: { user_id: this.userId, project_id: this.project } }\n );\n return result.entities || [];\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var RemembraError = class _RemembraError extends Error {
|
|
3
|
+
constructor(message, status, code) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = "RemembraError";
|
|
6
|
+
this.status = status;
|
|
7
|
+
this.code = code;
|
|
8
|
+
if (Error.captureStackTrace) {
|
|
9
|
+
Error.captureStackTrace(this, _RemembraError);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
var AuthenticationError = class extends RemembraError {
|
|
14
|
+
constructor(message = "Authentication failed") {
|
|
15
|
+
super(message, 401, "AUTH_ERROR");
|
|
16
|
+
this.name = "AuthenticationError";
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
var NotFoundError = class extends RemembraError {
|
|
20
|
+
constructor(message = "Resource not found") {
|
|
21
|
+
super(message, 404, "NOT_FOUND");
|
|
22
|
+
this.name = "NotFoundError";
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
var ValidationError = class extends RemembraError {
|
|
26
|
+
constructor(message) {
|
|
27
|
+
super(message, 422, "VALIDATION_ERROR");
|
|
28
|
+
this.name = "ValidationError";
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
var RateLimitError = class extends RemembraError {
|
|
32
|
+
constructor(message = "Rate limit exceeded", retryAfter) {
|
|
33
|
+
super(message, 429, "RATE_LIMITED");
|
|
34
|
+
this.name = "RateLimitError";
|
|
35
|
+
this.retryAfter = retryAfter;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
var ServerError = class extends RemembraError {
|
|
39
|
+
constructor(message = "Internal server error") {
|
|
40
|
+
super(message, 500, "SERVER_ERROR");
|
|
41
|
+
this.name = "ServerError";
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
var NetworkError = class extends RemembraError {
|
|
45
|
+
constructor(message = "Network error") {
|
|
46
|
+
super(message, void 0, "NETWORK_ERROR");
|
|
47
|
+
this.name = "NetworkError";
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
var TimeoutError = class extends RemembraError {
|
|
51
|
+
constructor(message = "Request timed out") {
|
|
52
|
+
super(message, void 0, "TIMEOUT");
|
|
53
|
+
this.name = "TimeoutError";
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// src/client.ts
|
|
58
|
+
var DEFAULT_URL = "http://localhost:8787";
|
|
59
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
60
|
+
var MAX_RETRIES = 3;
|
|
61
|
+
var RETRY_DELAY = 1e3;
|
|
62
|
+
var Remembra = class {
|
|
63
|
+
constructor(config) {
|
|
64
|
+
this.url = (config.url || DEFAULT_URL).replace(/\/$/, "");
|
|
65
|
+
this.apiKey = config.apiKey;
|
|
66
|
+
this.userId = config.userId;
|
|
67
|
+
this.project = config.project || "default";
|
|
68
|
+
this.timeout = config.timeout || DEFAULT_TIMEOUT;
|
|
69
|
+
this.debug = config.debug || false;
|
|
70
|
+
if (!this.userId) {
|
|
71
|
+
throw new ValidationError("userId is required");
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// ===========================================================================
|
|
75
|
+
// Private Methods
|
|
76
|
+
// ===========================================================================
|
|
77
|
+
log(...args) {
|
|
78
|
+
if (this.debug) {
|
|
79
|
+
console.log("[Remembra]", ...args);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async request(method, path, options = {}) {
|
|
83
|
+
const { body, params, retries = MAX_RETRIES } = options;
|
|
84
|
+
const url = new URL(`${this.url}${path}`);
|
|
85
|
+
if (params) {
|
|
86
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
87
|
+
if (value !== void 0) {
|
|
88
|
+
url.searchParams.set(key, value);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
const headers = {
|
|
93
|
+
"Content-Type": "application/json",
|
|
94
|
+
"User-Agent": "remembra-js/0.1.0"
|
|
95
|
+
};
|
|
96
|
+
if (this.apiKey) {
|
|
97
|
+
headers["X-API-Key"] = this.apiKey;
|
|
98
|
+
}
|
|
99
|
+
this.log(method, path, body ? JSON.stringify(body).slice(0, 100) : "");
|
|
100
|
+
let lastError;
|
|
101
|
+
for (let attempt = 0; attempt < retries; attempt++) {
|
|
102
|
+
try {
|
|
103
|
+
const controller = new AbortController();
|
|
104
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
105
|
+
const response = await fetch(url.toString(), {
|
|
106
|
+
method,
|
|
107
|
+
headers,
|
|
108
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
109
|
+
signal: controller.signal
|
|
110
|
+
});
|
|
111
|
+
clearTimeout(timeoutId);
|
|
112
|
+
if (response.ok) {
|
|
113
|
+
return await response.json();
|
|
114
|
+
}
|
|
115
|
+
const errorBody = await response.json().catch(() => ({}));
|
|
116
|
+
const errorMessage = errorBody.detail || response.statusText;
|
|
117
|
+
switch (response.status) {
|
|
118
|
+
case 401:
|
|
119
|
+
throw new AuthenticationError(errorMessage);
|
|
120
|
+
case 404:
|
|
121
|
+
throw new NotFoundError(errorMessage);
|
|
122
|
+
case 422:
|
|
123
|
+
throw new ValidationError(errorMessage);
|
|
124
|
+
case 429:
|
|
125
|
+
const retryAfter = parseInt(response.headers.get("Retry-After") || "60", 10);
|
|
126
|
+
if (attempt < retries - 1) {
|
|
127
|
+
this.log(`Rate limited, retrying in ${retryAfter}s...`);
|
|
128
|
+
await this.sleep(retryAfter * 1e3);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
throw new RateLimitError(errorMessage, retryAfter);
|
|
132
|
+
case 500:
|
|
133
|
+
case 502:
|
|
134
|
+
case 503:
|
|
135
|
+
case 504:
|
|
136
|
+
if (attempt < retries - 1) {
|
|
137
|
+
this.log(`Server error (${response.status}), retrying...`);
|
|
138
|
+
await this.sleep(RETRY_DELAY * Math.pow(2, attempt));
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
throw new ServerError(errorMessage);
|
|
142
|
+
default:
|
|
143
|
+
throw new RemembraError(errorMessage, response.status);
|
|
144
|
+
}
|
|
145
|
+
} catch (error) {
|
|
146
|
+
lastError = error;
|
|
147
|
+
if (error instanceof RemembraError) {
|
|
148
|
+
throw error;
|
|
149
|
+
}
|
|
150
|
+
if (error instanceof Error) {
|
|
151
|
+
if (error.name === "AbortError") {
|
|
152
|
+
throw new TimeoutError(`Request timed out after ${this.timeout}ms`);
|
|
153
|
+
}
|
|
154
|
+
if (attempt < retries - 1) {
|
|
155
|
+
this.log(`Network error, retrying...`, error.message);
|
|
156
|
+
await this.sleep(RETRY_DELAY * Math.pow(2, attempt));
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
throw new NetworkError(error.message);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
throw lastError || new NetworkError("Request failed");
|
|
164
|
+
}
|
|
165
|
+
sleep(ms) {
|
|
166
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
167
|
+
}
|
|
168
|
+
// ===========================================================================
|
|
169
|
+
// Core Operations
|
|
170
|
+
// ===========================================================================
|
|
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
|
+
async store(content, options = {}) {
|
|
188
|
+
return this.request("POST", "/api/v1/memories", {
|
|
189
|
+
body: {
|
|
190
|
+
user_id: this.userId,
|
|
191
|
+
project_id: this.project,
|
|
192
|
+
content,
|
|
193
|
+
metadata: options.metadata || {},
|
|
194
|
+
ttl: options.ttl
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Recall memories relevant to a query.
|
|
200
|
+
*
|
|
201
|
+
* @param query - Natural language query
|
|
202
|
+
* @param options - Recall options (limit, threshold, etc.)
|
|
203
|
+
* @returns Context string and matching memories
|
|
204
|
+
*
|
|
205
|
+
* @example
|
|
206
|
+
* ```typescript
|
|
207
|
+
* const result = await memory.recall('What are user preferences?');
|
|
208
|
+
* console.log(result.context); // Synthesized context
|
|
209
|
+
* console.log(result.memories); // Individual memories
|
|
210
|
+
* ```
|
|
211
|
+
*/
|
|
212
|
+
async recall(query, options = {}) {
|
|
213
|
+
return this.request("POST", "/api/v1/memories/recall", {
|
|
214
|
+
body: {
|
|
215
|
+
user_id: this.userId,
|
|
216
|
+
project_id: this.project,
|
|
217
|
+
query,
|
|
218
|
+
limit: options.limit || 5,
|
|
219
|
+
threshold: options.threshold || 0.4,
|
|
220
|
+
max_tokens: options.maxTokens,
|
|
221
|
+
enable_hybrid: options.enableHybrid,
|
|
222
|
+
enable_rerank: options.enableRerank
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Get a specific memory by ID.
|
|
228
|
+
*
|
|
229
|
+
* @param memoryId - Memory ID
|
|
230
|
+
* @returns Memory details
|
|
231
|
+
*/
|
|
232
|
+
async get(memoryId) {
|
|
233
|
+
return this.request("GET", `/api/v1/memories/${memoryId}`);
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Forget (delete) memories.
|
|
237
|
+
*
|
|
238
|
+
* @param options - What to delete (memoryId, entity, or all)
|
|
239
|
+
* @returns Deletion counts
|
|
240
|
+
*
|
|
241
|
+
* @example
|
|
242
|
+
* ```typescript
|
|
243
|
+
* // Delete specific memory
|
|
244
|
+
* await memory.forget({ memoryId: 'mem_123' });
|
|
245
|
+
*
|
|
246
|
+
* // Delete all about an entity
|
|
247
|
+
* await memory.forget({ entity: 'John' });
|
|
248
|
+
* ```
|
|
249
|
+
*/
|
|
250
|
+
async forget(options = {}) {
|
|
251
|
+
const params = {};
|
|
252
|
+
if (options.memoryId) {
|
|
253
|
+
params.memory_id = options.memoryId;
|
|
254
|
+
} else if (options.entity) {
|
|
255
|
+
params.entity = options.entity;
|
|
256
|
+
} else {
|
|
257
|
+
params.user_id = this.userId;
|
|
258
|
+
}
|
|
259
|
+
return this.request("DELETE", "/api/v1/memories", { params });
|
|
260
|
+
}
|
|
261
|
+
// ===========================================================================
|
|
262
|
+
// Conversation Ingestion
|
|
263
|
+
// ===========================================================================
|
|
264
|
+
/**
|
|
265
|
+
* Ingest a conversation and automatically extract memories.
|
|
266
|
+
*
|
|
267
|
+
* This is the primary method for AI agents to add conversation context
|
|
268
|
+
* to persistent memory without manually calling store for each fact.
|
|
269
|
+
*
|
|
270
|
+
* @param messages - Array of conversation messages
|
|
271
|
+
* @param options - Ingestion options
|
|
272
|
+
* @returns Extracted facts, entities, and stats
|
|
273
|
+
*
|
|
274
|
+
* @example
|
|
275
|
+
* ```typescript
|
|
276
|
+
* const result = await memory.ingestConversation([
|
|
277
|
+
* { role: 'user', content: 'My name is John and I work at Google' },
|
|
278
|
+
* { role: 'assistant', content: 'Nice to meet you, John!' },
|
|
279
|
+
* ], {
|
|
280
|
+
* minImportance: 0.5,
|
|
281
|
+
* });
|
|
282
|
+
*
|
|
283
|
+
* console.log(`Extracted ${result.stats.facts_extracted} facts`);
|
|
284
|
+
* console.log(`Stored ${result.stats.facts_stored} new memories`);
|
|
285
|
+
* ```
|
|
286
|
+
*/
|
|
287
|
+
async ingestConversation(messages, options = {}) {
|
|
288
|
+
return this.request("POST", "/api/v1/ingest/conversation", {
|
|
289
|
+
body: {
|
|
290
|
+
messages,
|
|
291
|
+
user_id: this.userId,
|
|
292
|
+
project_id: this.project,
|
|
293
|
+
session_id: options.sessionId,
|
|
294
|
+
options: {
|
|
295
|
+
extract_from: options.extractFrom || "both",
|
|
296
|
+
min_importance: options.minImportance ?? 0.5,
|
|
297
|
+
dedupe: options.dedupe ?? true,
|
|
298
|
+
store: options.store ?? true,
|
|
299
|
+
infer: options.infer ?? true
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
// ===========================================================================
|
|
305
|
+
// Utilities
|
|
306
|
+
// ===========================================================================
|
|
307
|
+
/**
|
|
308
|
+
* Check server health.
|
|
309
|
+
*
|
|
310
|
+
* @returns Health status
|
|
311
|
+
*/
|
|
312
|
+
async health() {
|
|
313
|
+
return this.request("GET", "/health");
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* List entities for the current user.
|
|
317
|
+
*
|
|
318
|
+
* @returns Array of entities
|
|
319
|
+
*/
|
|
320
|
+
async listEntities() {
|
|
321
|
+
const result = await this.request(
|
|
322
|
+
"GET",
|
|
323
|
+
"/api/v1/entities",
|
|
324
|
+
{ params: { user_id: this.userId, project_id: this.project } }
|
|
325
|
+
);
|
|
326
|
+
return result.entities || [];
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
export {
|
|
330
|
+
AuthenticationError,
|
|
331
|
+
NetworkError,
|
|
332
|
+
NotFoundError,
|
|
333
|
+
RateLimitError,
|
|
334
|
+
Remembra,
|
|
335
|
+
RemembraError,
|
|
336
|
+
ServerError,
|
|
337
|
+
TimeoutError,
|
|
338
|
+
ValidationError
|
|
339
|
+
};
|
|
340
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/client.ts"],"sourcesContent":["/**\n * Remembra SDK Error Classes\n */\n\nexport class RemembraError extends Error {\n public readonly status?: number;\n public readonly code?: string;\n\n constructor(message: string, status?: number, code?: string) {\n super(message);\n this.name = 'RemembraError';\n this.status = status;\n this.code = code;\n \n // Maintain proper stack trace in V8\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, RemembraError);\n }\n }\n}\n\nexport class AuthenticationError extends RemembraError {\n constructor(message = 'Authentication failed') {\n super(message, 401, 'AUTH_ERROR');\n this.name = 'AuthenticationError';\n }\n}\n\nexport class NotFoundError extends RemembraError {\n constructor(message = 'Resource not found') {\n super(message, 404, 'NOT_FOUND');\n this.name = 'NotFoundError';\n }\n}\n\nexport class ValidationError extends RemembraError {\n constructor(message: string) {\n super(message, 422, 'VALIDATION_ERROR');\n this.name = 'ValidationError';\n }\n}\n\nexport class RateLimitError extends RemembraError {\n public readonly retryAfter?: number;\n\n constructor(message = 'Rate limit exceeded', retryAfter?: number) {\n super(message, 429, 'RATE_LIMITED');\n this.name = 'RateLimitError';\n this.retryAfter = retryAfter;\n }\n}\n\nexport class ServerError extends RemembraError {\n constructor(message = 'Internal server error') {\n super(message, 500, 'SERVER_ERROR');\n this.name = 'ServerError';\n }\n}\n\nexport class NetworkError extends RemembraError {\n constructor(message = 'Network error') {\n super(message, undefined, 'NETWORK_ERROR');\n this.name = 'NetworkError';\n }\n}\n\nexport class TimeoutError extends RemembraError {\n constructor(message = 'Request timed out') {\n super(message, undefined, 'TIMEOUT');\n this.name = 'TimeoutError';\n }\n}\n","/**\n * Remembra TypeScript Client\n * \n * Main interface for the Remembra AI Memory Layer.\n * \n * @example\n * ```typescript\n * import { Remembra } from 'remembra';\n * \n * const memory = new Remembra({\n * url: 'http://localhost:8787',\n * apiKey: 'your-api-key',\n * userId: 'user_123',\n * });\n * \n * // Store a memory\n * const stored = await memory.store('User prefers dark mode');\n * \n * // Recall memories\n * const result = await memory.recall('What are user preferences?');\n * console.log(result.context);\n * \n * // Ingest a conversation\n * const ingestResult = await memory.ingestConversation([\n * { role: 'user', content: 'My name is John' },\n * { role: 'assistant', content: 'Nice to meet you, John!' },\n * ]);\n * ```\n */\n\nimport type {\n RemembraConfig,\n StoreOptions,\n StoreResult,\n RecallOptions,\n RecallResult,\n ForgetOptions,\n ForgetResult,\n Message,\n IngestOptions,\n IngestResult,\n Memory,\n EntityRef,\n} from './types';\n\nimport {\n RemembraError,\n AuthenticationError,\n NotFoundError,\n ValidationError,\n RateLimitError,\n ServerError,\n NetworkError,\n TimeoutError,\n} from './errors';\n\nconst DEFAULT_URL = 'http://localhost:8787';\nconst DEFAULT_TIMEOUT = 30000;\nconst MAX_RETRIES = 3;\nconst RETRY_DELAY = 1000;\n\nexport class Remembra {\n private readonly url: string;\n private readonly apiKey?: string;\n private readonly userId: string;\n private readonly project: string;\n private readonly timeout: number;\n private readonly debug: boolean;\n\n constructor(config: RemembraConfig) {\n this.url = (config.url || DEFAULT_URL).replace(/\\/$/, '');\n this.apiKey = config.apiKey;\n this.userId = config.userId;\n this.project = config.project || 'default';\n this.timeout = config.timeout || DEFAULT_TIMEOUT;\n this.debug = config.debug || false;\n\n if (!this.userId) {\n throw new ValidationError('userId is required');\n }\n }\n\n // ===========================================================================\n // Private Methods\n // ===========================================================================\n\n private log(...args: unknown[]): void {\n if (this.debug) {\n console.log('[Remembra]', ...args);\n }\n }\n\n private async request<T>(\n method: string,\n path: string,\n options: {\n body?: unknown;\n params?: Record<string, string>;\n retries?: number;\n } = {}\n ): Promise<T> {\n const { body, params, retries = MAX_RETRIES } = options;\n\n // Build URL with query params\n const url = new URL(`${this.url}${path}`);\n if (params) {\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined) {\n url.searchParams.set(key, value);\n }\n });\n }\n\n // Build headers\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'User-Agent': 'remembra-js/0.1.0',\n };\n if (this.apiKey) {\n headers['X-API-Key'] = this.apiKey;\n }\n\n this.log(method, path, body ? JSON.stringify(body).slice(0, 100) : '');\n\n // Execute with retry\n let lastError: Error | undefined;\n \n for (let attempt = 0; attempt < retries; attempt++) {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n const response = await fetch(url.toString(), {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n // Handle response\n if (response.ok) {\n return await response.json() as T;\n }\n\n // Handle errors\n const errorBody = await response.json().catch(() => ({})) as { detail?: string };\n const errorMessage = errorBody.detail || response.statusText;\n\n switch (response.status) {\n case 401:\n throw new AuthenticationError(errorMessage);\n case 404:\n throw new NotFoundError(errorMessage);\n case 422:\n throw new ValidationError(errorMessage);\n case 429:\n const retryAfter = parseInt(response.headers.get('Retry-After') || '60', 10);\n if (attempt < retries - 1) {\n this.log(`Rate limited, retrying in ${retryAfter}s...`);\n await this.sleep(retryAfter * 1000);\n continue;\n }\n throw new RateLimitError(errorMessage, retryAfter);\n case 500:\n case 502:\n case 503:\n case 504:\n if (attempt < retries - 1) {\n this.log(`Server error (${response.status}), retrying...`);\n await this.sleep(RETRY_DELAY * Math.pow(2, attempt));\n continue;\n }\n throw new ServerError(errorMessage);\n default:\n throw new RemembraError(errorMessage, response.status);\n }\n } catch (error) {\n lastError = error as Error;\n\n if (error instanceof RemembraError) {\n throw error;\n }\n\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n throw new TimeoutError(`Request timed out after ${this.timeout}ms`);\n }\n if (attempt < retries - 1) {\n this.log(`Network error, retrying...`, error.message);\n await this.sleep(RETRY_DELAY * Math.pow(2, attempt));\n continue;\n }\n throw new NetworkError(error.message);\n }\n }\n }\n\n throw lastError || new NetworkError('Request failed');\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n // ===========================================================================\n // Core Operations\n // ===========================================================================\n\n /**\n * Store a new memory.\n * \n * @param content - Text content to memorize\n * @param options - Optional metadata and TTL\n * @returns Stored memory with extracted facts and entities\n * \n * @example\n * ```typescript\n * const result = await memory.store('User prefers dark mode', {\n * metadata: { source: 'settings' },\n * ttl: '30d',\n * });\n * console.log(result.extracted_facts);\n * ```\n */\n async store(content: string, options: StoreOptions = {}): Promise<StoreResult> {\n return this.request<StoreResult>('POST', '/api/v1/memories', {\n body: {\n user_id: this.userId,\n project_id: this.project,\n content,\n metadata: options.metadata || {},\n ttl: options.ttl,\n },\n });\n }\n\n /**\n * Recall memories relevant to a query.\n * \n * @param query - Natural language query\n * @param options - Recall options (limit, threshold, etc.)\n * @returns Context string and matching memories\n * \n * @example\n * ```typescript\n * const result = await memory.recall('What are user preferences?');\n * console.log(result.context); // Synthesized context\n * console.log(result.memories); // Individual memories\n * ```\n */\n async recall(query: string, options: RecallOptions = {}): Promise<RecallResult> {\n return this.request<RecallResult>('POST', '/api/v1/memories/recall', {\n body: {\n user_id: this.userId,\n project_id: this.project,\n query,\n limit: options.limit || 5,\n threshold: options.threshold || 0.4,\n max_tokens: options.maxTokens,\n enable_hybrid: options.enableHybrid,\n enable_rerank: options.enableRerank,\n },\n });\n }\n\n /**\n * Get a specific memory by ID.\n * \n * @param memoryId - Memory ID\n * @returns Memory details\n */\n async get(memoryId: string): Promise<Memory> {\n return this.request<Memory>('GET', `/api/v1/memories/${memoryId}`);\n }\n\n /**\n * Forget (delete) memories.\n * \n * @param options - What to delete (memoryId, entity, or all)\n * @returns Deletion counts\n * \n * @example\n * ```typescript\n * // Delete specific memory\n * await memory.forget({ memoryId: 'mem_123' });\n * \n * // Delete all about an entity\n * await memory.forget({ entity: 'John' });\n * ```\n */\n async forget(options: ForgetOptions = {}): Promise<ForgetResult> {\n const params: Record<string, string> = {};\n \n if (options.memoryId) {\n params.memory_id = options.memoryId;\n } else if (options.entity) {\n params.entity = options.entity;\n } else {\n params.user_id = this.userId;\n }\n\n return this.request<ForgetResult>('DELETE', '/api/v1/memories', { params });\n }\n\n // ===========================================================================\n // Conversation Ingestion\n // ===========================================================================\n\n /**\n * Ingest a conversation and automatically extract memories.\n * \n * This is the primary method for AI agents to add conversation context\n * to persistent memory without manually calling store for each fact.\n * \n * @param messages - Array of conversation messages\n * @param options - Ingestion options\n * @returns Extracted facts, entities, and stats\n * \n * @example\n * ```typescript\n * const result = await memory.ingestConversation([\n * { role: 'user', content: 'My name is John and I work at Google' },\n * { role: 'assistant', content: 'Nice to meet you, John!' },\n * ], {\n * minImportance: 0.5,\n * });\n * \n * console.log(`Extracted ${result.stats.facts_extracted} facts`);\n * console.log(`Stored ${result.stats.facts_stored} new memories`);\n * ```\n */\n async ingestConversation(\n messages: Message[],\n options: IngestOptions = {}\n ): Promise<IngestResult> {\n return this.request<IngestResult>('POST', '/api/v1/ingest/conversation', {\n body: {\n messages,\n user_id: this.userId,\n project_id: this.project,\n session_id: options.sessionId,\n options: {\n extract_from: options.extractFrom || 'both',\n min_importance: options.minImportance ?? 0.5,\n dedupe: options.dedupe ?? true,\n store: options.store ?? true,\n infer: options.infer ?? true,\n },\n },\n });\n }\n\n // ===========================================================================\n // Utilities\n // ===========================================================================\n\n /**\n * Check server health.\n * \n * @returns Health status\n */\n async health(): Promise<Record<string, unknown>> {\n return this.request<Record<string, unknown>>('GET', '/health');\n }\n\n /**\n * List entities for the current user.\n * \n * @returns Array of entities\n */\n async listEntities(): Promise<EntityRef[]> {\n const result = await this.request<{ entities: EntityRef[] }>(\n 'GET',\n '/api/v1/entities',\n { params: { user_id: this.userId, project_id: this.project } }\n );\n return result.entities || [];\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "remembra",
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "TypeScript/JavaScript SDK for Remembra - AI Memory Layer",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsup",
|
|
21
|
+
"test": "vitest run",
|
|
22
|
+
"test:watch": "vitest",
|
|
23
|
+
"lint": "eslint src/",
|
|
24
|
+
"typecheck": "tsc --noEmit",
|
|
25
|
+
"prepublishOnly": "npm run build"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"remembra",
|
|
29
|
+
"ai",
|
|
30
|
+
"memory",
|
|
31
|
+
"llm",
|
|
32
|
+
"agent",
|
|
33
|
+
"rag",
|
|
34
|
+
"vector",
|
|
35
|
+
"embedding"
|
|
36
|
+
],
|
|
37
|
+
"author": "DolphyTech <admin@dolphytech.com>",
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"homepage": "https://remembra.dev",
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "https://github.com/remembra-ai/remembra.git",
|
|
43
|
+
"directory": "sdk/typescript"
|
|
44
|
+
},
|
|
45
|
+
"bugs": {
|
|
46
|
+
"url": "https://github.com/remembra-ai/remembra/issues"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/node": "^20.0.0",
|
|
50
|
+
"tsup": "^8.0.0",
|
|
51
|
+
"typescript": "^5.0.0",
|
|
52
|
+
"vitest": "^1.0.0"
|
|
53
|
+
},
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=18.0.0"
|
|
56
|
+
}
|
|
57
|
+
}
|