@memorylayerai/sdk 0.3.1 → 0.5.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 +43 -53
- package/dist/index.cjs +107 -27
- package/dist/index.d.cts +67 -11
- package/dist/index.d.ts +67 -11
- package/dist/index.js +107 -27
- package/package.json +1 -1
- package/src/resources/ingest.ts +82 -15
- package/src/resources/search.ts +44 -16
- package/src/types.ts +41 -9
package/README.md
CHANGED
|
@@ -28,30 +28,30 @@ yarn add @memorylayerai/sdk
|
|
|
28
28
|
|
|
29
29
|
## Quick Start
|
|
30
30
|
|
|
31
|
-
### Option 1: Transparent Router (
|
|
31
|
+
### Option 1: Transparent Router (Beta) - Drop-in OpenAI Proxy ⚡
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
Change your baseURL to add automatic memory injection:
|
|
34
34
|
|
|
35
35
|
```typescript
|
|
36
36
|
import OpenAI from 'openai';
|
|
37
37
|
|
|
38
38
|
const openai = new OpenAI({
|
|
39
|
-
baseURL: 'https://api.memorylayer.ai/v1', // ←
|
|
39
|
+
baseURL: 'https://api.memorylayer.ai/v1', // ← Point to MemoryLayer
|
|
40
40
|
apiKey: 'ml_your_memorylayer_key' // ← Use your MemoryLayer key
|
|
41
41
|
});
|
|
42
42
|
|
|
43
|
-
//
|
|
43
|
+
// Memory is automatically retrieved and injected
|
|
44
44
|
const response = await openai.chat.completions.create({
|
|
45
45
|
model: 'gpt-4',
|
|
46
46
|
messages: [{ role: 'user', content: 'What are my preferences?' }]
|
|
47
47
|
});
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
**
|
|
51
|
-
- ✅
|
|
52
|
-
- ✅
|
|
53
|
-
- ✅
|
|
54
|
-
-
|
|
50
|
+
**Current Status:**
|
|
51
|
+
- ✅ Works with `/v1/chat/completions` (non-streaming)
|
|
52
|
+
- ✅ OpenAI-compatible responses
|
|
53
|
+
- ✅ Configurable via headers (use `fetch`/`axios` for guaranteed header support)
|
|
54
|
+
- ⏳ Streaming support coming soon
|
|
55
55
|
|
|
56
56
|
See [Transparent Router Guide](#transparent-router) for details.
|
|
57
57
|
|
|
@@ -115,7 +115,12 @@ results.forEach(result => {
|
|
|
115
115
|
|
|
116
116
|
## Transparent Router
|
|
117
117
|
|
|
118
|
-
The transparent router is an OpenAI-compatible proxy that automatically injects memory context into your requests.
|
|
118
|
+
The transparent router is an OpenAI-compatible proxy that automatically injects memory context into your requests.
|
|
119
|
+
|
|
120
|
+
**Current Status:**
|
|
121
|
+
- ✅ Works with `/v1/chat/completions` (non-streaming)
|
|
122
|
+
- ✅ OpenAI-compatible responses
|
|
123
|
+
- ⏳ Streaming support coming soon
|
|
119
124
|
|
|
120
125
|
### Basic Usage
|
|
121
126
|
|
|
@@ -135,67 +140,52 @@ const response = await openai.chat.completions.create({
|
|
|
135
140
|
|
|
136
141
|
### Configuration Headers
|
|
137
142
|
|
|
138
|
-
Control memory injection with optional headers:
|
|
143
|
+
Control memory injection with optional headers. **Note:** For guaranteed header support, use `fetch` or `axios` directly:
|
|
139
144
|
|
|
140
145
|
```typescript
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
146
|
+
// Using fetch for guaranteed header support
|
|
147
|
+
const response = await fetch('https://api.memorylayer.ai/v1/chat/completions', {
|
|
148
|
+
method: 'POST',
|
|
144
149
|
headers: {
|
|
145
|
-
'
|
|
146
|
-
'
|
|
147
|
-
'x-memory-
|
|
148
|
-
'x-memory-
|
|
149
|
-
'x-memory-
|
|
150
|
-
'x-memory-
|
|
151
|
-
|
|
150
|
+
'Authorization': `Bearer ${process.env.MEMORYLAYER_API_KEY}`,
|
|
151
|
+
'Content-Type': 'application/json',
|
|
152
|
+
'x-memory-user-id': 'user_123', // User scope (required for multi-user apps)
|
|
153
|
+
'x-memory-session-id': 'sess_abc', // Session scope (persist from response)
|
|
154
|
+
'x-memory-limit': '10', // Max memories to inject
|
|
155
|
+
'x-memory-injection-mode': 'safe', // safe|full (balanced coming soon)
|
|
156
|
+
'x-memory-disabled': 'false' // Enable/disable memory
|
|
157
|
+
},
|
|
158
|
+
body: JSON.stringify({
|
|
159
|
+
model: 'gpt-4',
|
|
160
|
+
messages: [{ role: 'user', content: 'Hello!' }]
|
|
161
|
+
})
|
|
152
162
|
});
|
|
153
163
|
```
|
|
154
164
|
|
|
155
165
|
### Injection Modes
|
|
156
166
|
|
|
157
|
-
- **safe
|
|
158
|
-
- **
|
|
159
|
-
- **
|
|
167
|
+
- **safe** (default): Only fact + preference types (minimal risk, structured data)
|
|
168
|
+
- **full**: All memory types including snippets (maximum context, higher token usage)
|
|
169
|
+
- **balanced**: Trusted summaries + facts + preferences (coming soon)
|
|
160
170
|
|
|
161
171
|
### Diagnostic Headers
|
|
162
172
|
|
|
163
|
-
Every response includes diagnostic headers:
|
|
173
|
+
Every response includes diagnostic headers showing what happened:
|
|
164
174
|
|
|
165
175
|
```typescript
|
|
166
|
-
const response = await
|
|
167
|
-
|
|
168
|
-
console.log('Memories retrieved:', response.headers?.['x-memory-hit-count']);
|
|
169
|
-
console.log('Tokens injected:', response.headers?.['x-memory-injected-tokens']);
|
|
170
|
-
console.log('Max score:', response.headers?.['x-memory-max-score']);
|
|
171
|
-
console.log('Query rewriting:', response.headers?.['x-memory-rewrite']);
|
|
172
|
-
console.log('Memory status:', response.headers?.['x-memory-status']);
|
|
173
|
-
console.log('Session ID:', response.headers?.['x-memory-session-id']);
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
### Streaming Support
|
|
176
|
+
const response = await fetch('https://api.memorylayer.ai/v1/chat/completions', { ... });
|
|
177
177
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
stream: true,
|
|
185
|
-
headers: {
|
|
186
|
-
'x-memory-user-id': 'user_123'
|
|
187
|
-
}
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
for await (const chunk of stream) {
|
|
191
|
-
const content = chunk.choices[0]?.delta?.content || '';
|
|
192
|
-
process.stdout.write(content);
|
|
193
|
-
}
|
|
178
|
+
console.log('Memories retrieved:', response.headers.get('x-memory-hit-count'));
|
|
179
|
+
console.log('Tokens injected:', response.headers.get('x-memory-injected-tokens'));
|
|
180
|
+
console.log('Max score:', response.headers.get('x-memory-max-score'));
|
|
181
|
+
console.log('Query rewriting:', response.headers.get('x-memory-rewrite'));
|
|
182
|
+
console.log('Memory status:', response.headers.get('x-memory-status'));
|
|
183
|
+
console.log('Session ID:', response.headers.get('x-memory-session-id')); // Persist this!
|
|
194
184
|
```
|
|
195
185
|
|
|
196
186
|
### Session Management
|
|
197
187
|
|
|
198
|
-
|
|
188
|
+
For chat applications, persist `x-memory-session-id` from response headers and pass it in subsequent requests:
|
|
199
189
|
|
|
200
190
|
```typescript
|
|
201
191
|
const response = await openai.chat.completions.create({ ... });
|
package/dist/index.cjs
CHANGED
|
@@ -221,9 +221,18 @@ var init_search = __esm({
|
|
|
221
221
|
this.httpClient = httpClient;
|
|
222
222
|
}
|
|
223
223
|
/**
|
|
224
|
-
* Search memories
|
|
224
|
+
* Search memories using the unified /v1/search endpoint with hybrid retrieval.
|
|
225
|
+
*
|
|
226
|
+
* This uses the app's full retrieval pipeline with:
|
|
227
|
+
* - Vector similarity search
|
|
228
|
+
* - BM25 keyword search
|
|
229
|
+
* - Recency scoring
|
|
230
|
+
* - Graph connectivity (optional)
|
|
231
|
+
* - Entity expansion (optional)
|
|
232
|
+
* - LLM/Cross-encoder reranking (optional)
|
|
233
|
+
*
|
|
225
234
|
* @param request - Search request
|
|
226
|
-
* @returns Search results
|
|
235
|
+
* @returns Search results with memory pack structure
|
|
227
236
|
*/
|
|
228
237
|
async search(request) {
|
|
229
238
|
if (!request.query || request.query.trim().length === 0) {
|
|
@@ -238,24 +247,36 @@ var init_search = __esm({
|
|
|
238
247
|
[{ field: "projectId", message: "Project ID is required" }]
|
|
239
248
|
);
|
|
240
249
|
}
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
|
|
250
|
+
const body = {
|
|
251
|
+
query: request.query,
|
|
252
|
+
project_id: request.projectId,
|
|
253
|
+
include_text_format: true
|
|
244
254
|
};
|
|
245
255
|
if (request.limit !== void 0) {
|
|
246
|
-
|
|
247
|
-
}
|
|
248
|
-
if (request.threshold !== void 0) {
|
|
249
|
-
query.threshold = request.threshold.toString();
|
|
250
|
-
}
|
|
251
|
-
if (request.filter) {
|
|
252
|
-
query.filter = JSON.stringify(request.filter);
|
|
256
|
+
body.limit = request.limit;
|
|
253
257
|
}
|
|
254
|
-
|
|
255
|
-
|
|
258
|
+
body.rerank_strategy = request.rerankingStrategy || "cross-encoder";
|
|
259
|
+
const response = await this.httpClient.request({
|
|
260
|
+
method: "POST",
|
|
256
261
|
path: "/v1/search",
|
|
257
|
-
|
|
262
|
+
body
|
|
258
263
|
});
|
|
264
|
+
const memoryPack = response.memory_pack || {};
|
|
265
|
+
const results = [];
|
|
266
|
+
for (const memoryType of ["facts", "preferences", "entities", "sources"]) {
|
|
267
|
+
const items = memoryPack[memoryType] || [];
|
|
268
|
+
for (const item of items) {
|
|
269
|
+
results.push({
|
|
270
|
+
memory: item,
|
|
271
|
+
score: item.score || 1,
|
|
272
|
+
highlights: item.highlights || []
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return {
|
|
277
|
+
results,
|
|
278
|
+
total: results.length
|
|
279
|
+
};
|
|
259
280
|
}
|
|
260
281
|
};
|
|
261
282
|
}
|
|
@@ -293,18 +314,15 @@ var init_ingest = __esm({
|
|
|
293
314
|
[{ field: "projectId", message: "Project ID is required" }]
|
|
294
315
|
);
|
|
295
316
|
}
|
|
296
|
-
const body = {
|
|
297
|
-
projectId: request.projectId,
|
|
298
|
-
metadata: request.metadata,
|
|
299
|
-
chunkSize: request.chunkSize,
|
|
300
|
-
chunkOverlap: request.chunkOverlap,
|
|
301
|
-
// In a real implementation, you'd convert the file to base64 or use FormData
|
|
302
|
-
file: request.file
|
|
303
|
-
};
|
|
304
317
|
return this.httpClient.request({
|
|
305
318
|
method: "POST",
|
|
306
|
-
path: "/v1/ingest
|
|
307
|
-
body
|
|
319
|
+
path: "/v1/ingest",
|
|
320
|
+
body: {
|
|
321
|
+
type: "pdf",
|
|
322
|
+
projectId: request.projectId,
|
|
323
|
+
metadata: request.metadata || {},
|
|
324
|
+
file: request.file
|
|
325
|
+
}
|
|
308
326
|
});
|
|
309
327
|
}
|
|
310
328
|
/**
|
|
@@ -327,9 +345,71 @@ var init_ingest = __esm({
|
|
|
327
345
|
}
|
|
328
346
|
return this.httpClient.request({
|
|
329
347
|
method: "POST",
|
|
330
|
-
path: "/v1/ingest
|
|
331
|
-
body:
|
|
348
|
+
path: "/v1/ingest",
|
|
349
|
+
body: {
|
|
350
|
+
type: "text",
|
|
351
|
+
content: request.text,
|
|
352
|
+
projectId: request.projectId,
|
|
353
|
+
metadata: request.metadata || {}
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Ingest content from a URL
|
|
359
|
+
* @param url - URL to ingest from
|
|
360
|
+
* @param projectId - Project ID
|
|
361
|
+
* @param metadata - Optional metadata
|
|
362
|
+
* @returns Ingestion response with job details
|
|
363
|
+
*/
|
|
364
|
+
async url(url, projectId, metadata) {
|
|
365
|
+
if (!url || url.trim().length === 0) {
|
|
366
|
+
throw new ValidationError(
|
|
367
|
+
"URL cannot be empty",
|
|
368
|
+
[{ field: "url", message: "URL is required and cannot be empty" }]
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
if (!projectId || projectId.trim().length === 0) {
|
|
372
|
+
throw new ValidationError(
|
|
373
|
+
"Project ID is required",
|
|
374
|
+
[{ field: "projectId", message: "Project ID is required" }]
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
return this.httpClient.request({
|
|
378
|
+
method: "POST",
|
|
379
|
+
path: "/v1/ingest",
|
|
380
|
+
body: {
|
|
381
|
+
type: "url",
|
|
382
|
+
url,
|
|
383
|
+
projectId,
|
|
384
|
+
metadata: metadata || {}
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Get the status of an ingestion job
|
|
390
|
+
* @param jobId - Job ID returned from ingest
|
|
391
|
+
* @param projectId - Project ID
|
|
392
|
+
* @returns Job status information
|
|
393
|
+
*/
|
|
394
|
+
async getJob(jobId, projectId) {
|
|
395
|
+
if (!jobId || jobId.trim().length === 0) {
|
|
396
|
+
throw new ValidationError(
|
|
397
|
+
"Job ID is required",
|
|
398
|
+
[{ field: "jobId", message: "Job ID is required" }]
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
if (!projectId || projectId.trim().length === 0) {
|
|
402
|
+
throw new ValidationError(
|
|
403
|
+
"Project ID is required",
|
|
404
|
+
[{ field: "projectId", message: "Project ID is required" }]
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
const response = await this.httpClient.request({
|
|
408
|
+
method: "GET",
|
|
409
|
+
path: `/v1/jobs/${jobId}`,
|
|
410
|
+
query: { projectId }
|
|
332
411
|
});
|
|
412
|
+
return response.data || response;
|
|
333
413
|
}
|
|
334
414
|
};
|
|
335
415
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -163,12 +163,30 @@ interface SearchRequest {
|
|
|
163
163
|
query: string;
|
|
164
164
|
/** Project ID to search in */
|
|
165
165
|
projectId: string;
|
|
166
|
-
/** Maximum number of results to return (default: 10) */
|
|
166
|
+
/** Maximum number of results to return (default: 10 - supermemory production default) */
|
|
167
167
|
limit?: number;
|
|
168
168
|
/** Filter criteria for search */
|
|
169
169
|
filter?: Record<string, any>;
|
|
170
|
-
/** Minimum relevance score threshold (0-1) */
|
|
170
|
+
/** Minimum relevance score threshold (0-1, default: 0.6 - supermemory production default for broad recall) */
|
|
171
171
|
threshold?: number;
|
|
172
|
+
/** Enable query rewriting (default: false - adds ~400ms latency) */
|
|
173
|
+
enableQueryRewriting?: boolean;
|
|
174
|
+
/** Enable entity expansion search (default: false) */
|
|
175
|
+
enableEntityExpansion?: boolean;
|
|
176
|
+
/** Enable graph connectivity search (default: false) */
|
|
177
|
+
enableGraphConnectivity?: boolean;
|
|
178
|
+
/** Enable semantic deduplication (default: false) */
|
|
179
|
+
enableSemanticDedup?: boolean;
|
|
180
|
+
/** Reranking strategy: 'none', 'cross-encoder', 'llm' (default: 'none' - adds latency) */
|
|
181
|
+
rerankingStrategy?: 'none' | 'cross-encoder' | 'llm';
|
|
182
|
+
/** Custom fusion weights for multi-method retrieval */
|
|
183
|
+
fusionWeights?: {
|
|
184
|
+
vector?: number;
|
|
185
|
+
bm25?: number;
|
|
186
|
+
recency?: number;
|
|
187
|
+
entity?: number;
|
|
188
|
+
graph?: number;
|
|
189
|
+
};
|
|
172
190
|
}
|
|
173
191
|
/**
|
|
174
192
|
* Search result
|
|
@@ -180,6 +198,20 @@ interface SearchResult {
|
|
|
180
198
|
score: number;
|
|
181
199
|
/** Highlighted text snippets */
|
|
182
200
|
highlights?: string[];
|
|
201
|
+
/** Score breakdown by retrieval method */
|
|
202
|
+
scoreBreakdown?: {
|
|
203
|
+
vectorScore?: number;
|
|
204
|
+
bm25Score?: number;
|
|
205
|
+
recencyScore?: number;
|
|
206
|
+
entityScore?: number;
|
|
207
|
+
graphScore?: number;
|
|
208
|
+
};
|
|
209
|
+
/** Connected memories (if graph enhancement enabled) */
|
|
210
|
+
connections?: Array<{
|
|
211
|
+
memoryId: string;
|
|
212
|
+
connectionType: 'updates' | 'extends' | 'derives' | 'similarity';
|
|
213
|
+
connectionStrength: number;
|
|
214
|
+
}>;
|
|
183
215
|
}
|
|
184
216
|
/**
|
|
185
217
|
* Search response
|
|
@@ -200,9 +232,9 @@ interface IngestFileRequest {
|
|
|
200
232
|
projectId: string;
|
|
201
233
|
/** Optional metadata to associate with ingested memories */
|
|
202
234
|
metadata?: Record<string, any>;
|
|
203
|
-
/** Chunk size for splitting the file (default:
|
|
235
|
+
/** Chunk size for splitting the file (default: 512 tokens - supermemory production default) */
|
|
204
236
|
chunkSize?: number;
|
|
205
|
-
/** Overlap between chunks (default:
|
|
237
|
+
/** Overlap between chunks (default: 10% - supermemory production default) */
|
|
206
238
|
chunkOverlap?: number;
|
|
207
239
|
}
|
|
208
240
|
/**
|
|
@@ -215,9 +247,9 @@ interface IngestTextRequest {
|
|
|
215
247
|
projectId: string;
|
|
216
248
|
/** Optional metadata to associate with ingested memories */
|
|
217
249
|
metadata?: Record<string, any>;
|
|
218
|
-
/** Chunk size for splitting the text (default:
|
|
250
|
+
/** Chunk size for splitting the text (default: 512 tokens - supermemory production default) */
|
|
219
251
|
chunkSize?: number;
|
|
220
|
-
/** Overlap between chunks (default:
|
|
252
|
+
/** Overlap between chunks (default: 10% - supermemory production default) */
|
|
221
253
|
chunkOverlap?: number;
|
|
222
254
|
}
|
|
223
255
|
/**
|
|
@@ -246,11 +278,11 @@ interface RouterRequest {
|
|
|
246
278
|
messages: Message[];
|
|
247
279
|
/** Project ID for memory context */
|
|
248
280
|
projectId: string;
|
|
249
|
-
/** Model to use (
|
|
281
|
+
/** Model to use (default: 'gpt-4o-mini' - supermemory production default) */
|
|
250
282
|
model?: string;
|
|
251
|
-
/** Temperature for generation (0-2, default:
|
|
283
|
+
/** Temperature for generation (0-2, default: 0.7 - supermemory production default) */
|
|
252
284
|
temperature?: number;
|
|
253
|
-
/** Maximum tokens to generate */
|
|
285
|
+
/** Maximum tokens to generate (default: 2000 - supermemory production default) */
|
|
254
286
|
maxTokens?: number;
|
|
255
287
|
/** Whether to stream the response */
|
|
256
288
|
stream?: boolean;
|
|
@@ -612,9 +644,18 @@ declare class SearchResource {
|
|
|
612
644
|
private httpClient;
|
|
613
645
|
constructor(httpClient: HTTPClient);
|
|
614
646
|
/**
|
|
615
|
-
* Search memories
|
|
647
|
+
* Search memories using the unified /v1/search endpoint with hybrid retrieval.
|
|
648
|
+
*
|
|
649
|
+
* This uses the app's full retrieval pipeline with:
|
|
650
|
+
* - Vector similarity search
|
|
651
|
+
* - BM25 keyword search
|
|
652
|
+
* - Recency scoring
|
|
653
|
+
* - Graph connectivity (optional)
|
|
654
|
+
* - Entity expansion (optional)
|
|
655
|
+
* - LLM/Cross-encoder reranking (optional)
|
|
656
|
+
*
|
|
616
657
|
* @param request - Search request
|
|
617
|
-
* @returns Search results
|
|
658
|
+
* @returns Search results with memory pack structure
|
|
618
659
|
*/
|
|
619
660
|
search(request: SearchRequest): Promise<SearchResponse>;
|
|
620
661
|
}
|
|
@@ -637,6 +678,21 @@ declare class IngestResource {
|
|
|
637
678
|
* @returns Ingestion response with created memory IDs
|
|
638
679
|
*/
|
|
639
680
|
text(request: IngestTextRequest): Promise<IngestResponse>;
|
|
681
|
+
/**
|
|
682
|
+
* Ingest content from a URL
|
|
683
|
+
* @param url - URL to ingest from
|
|
684
|
+
* @param projectId - Project ID
|
|
685
|
+
* @param metadata - Optional metadata
|
|
686
|
+
* @returns Ingestion response with job details
|
|
687
|
+
*/
|
|
688
|
+
url(url: string, projectId: string, metadata?: Record<string, any>): Promise<IngestResponse>;
|
|
689
|
+
/**
|
|
690
|
+
* Get the status of an ingestion job
|
|
691
|
+
* @param jobId - Job ID returned from ingest
|
|
692
|
+
* @param projectId - Project ID
|
|
693
|
+
* @returns Job status information
|
|
694
|
+
*/
|
|
695
|
+
getJob(jobId: string, projectId: string): Promise<any>;
|
|
640
696
|
}
|
|
641
697
|
|
|
642
698
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -163,12 +163,30 @@ interface SearchRequest {
|
|
|
163
163
|
query: string;
|
|
164
164
|
/** Project ID to search in */
|
|
165
165
|
projectId: string;
|
|
166
|
-
/** Maximum number of results to return (default: 10) */
|
|
166
|
+
/** Maximum number of results to return (default: 10 - supermemory production default) */
|
|
167
167
|
limit?: number;
|
|
168
168
|
/** Filter criteria for search */
|
|
169
169
|
filter?: Record<string, any>;
|
|
170
|
-
/** Minimum relevance score threshold (0-1) */
|
|
170
|
+
/** Minimum relevance score threshold (0-1, default: 0.6 - supermemory production default for broad recall) */
|
|
171
171
|
threshold?: number;
|
|
172
|
+
/** Enable query rewriting (default: false - adds ~400ms latency) */
|
|
173
|
+
enableQueryRewriting?: boolean;
|
|
174
|
+
/** Enable entity expansion search (default: false) */
|
|
175
|
+
enableEntityExpansion?: boolean;
|
|
176
|
+
/** Enable graph connectivity search (default: false) */
|
|
177
|
+
enableGraphConnectivity?: boolean;
|
|
178
|
+
/** Enable semantic deduplication (default: false) */
|
|
179
|
+
enableSemanticDedup?: boolean;
|
|
180
|
+
/** Reranking strategy: 'none', 'cross-encoder', 'llm' (default: 'none' - adds latency) */
|
|
181
|
+
rerankingStrategy?: 'none' | 'cross-encoder' | 'llm';
|
|
182
|
+
/** Custom fusion weights for multi-method retrieval */
|
|
183
|
+
fusionWeights?: {
|
|
184
|
+
vector?: number;
|
|
185
|
+
bm25?: number;
|
|
186
|
+
recency?: number;
|
|
187
|
+
entity?: number;
|
|
188
|
+
graph?: number;
|
|
189
|
+
};
|
|
172
190
|
}
|
|
173
191
|
/**
|
|
174
192
|
* Search result
|
|
@@ -180,6 +198,20 @@ interface SearchResult {
|
|
|
180
198
|
score: number;
|
|
181
199
|
/** Highlighted text snippets */
|
|
182
200
|
highlights?: string[];
|
|
201
|
+
/** Score breakdown by retrieval method */
|
|
202
|
+
scoreBreakdown?: {
|
|
203
|
+
vectorScore?: number;
|
|
204
|
+
bm25Score?: number;
|
|
205
|
+
recencyScore?: number;
|
|
206
|
+
entityScore?: number;
|
|
207
|
+
graphScore?: number;
|
|
208
|
+
};
|
|
209
|
+
/** Connected memories (if graph enhancement enabled) */
|
|
210
|
+
connections?: Array<{
|
|
211
|
+
memoryId: string;
|
|
212
|
+
connectionType: 'updates' | 'extends' | 'derives' | 'similarity';
|
|
213
|
+
connectionStrength: number;
|
|
214
|
+
}>;
|
|
183
215
|
}
|
|
184
216
|
/**
|
|
185
217
|
* Search response
|
|
@@ -200,9 +232,9 @@ interface IngestFileRequest {
|
|
|
200
232
|
projectId: string;
|
|
201
233
|
/** Optional metadata to associate with ingested memories */
|
|
202
234
|
metadata?: Record<string, any>;
|
|
203
|
-
/** Chunk size for splitting the file (default:
|
|
235
|
+
/** Chunk size for splitting the file (default: 512 tokens - supermemory production default) */
|
|
204
236
|
chunkSize?: number;
|
|
205
|
-
/** Overlap between chunks (default:
|
|
237
|
+
/** Overlap between chunks (default: 10% - supermemory production default) */
|
|
206
238
|
chunkOverlap?: number;
|
|
207
239
|
}
|
|
208
240
|
/**
|
|
@@ -215,9 +247,9 @@ interface IngestTextRequest {
|
|
|
215
247
|
projectId: string;
|
|
216
248
|
/** Optional metadata to associate with ingested memories */
|
|
217
249
|
metadata?: Record<string, any>;
|
|
218
|
-
/** Chunk size for splitting the text (default:
|
|
250
|
+
/** Chunk size for splitting the text (default: 512 tokens - supermemory production default) */
|
|
219
251
|
chunkSize?: number;
|
|
220
|
-
/** Overlap between chunks (default:
|
|
252
|
+
/** Overlap between chunks (default: 10% - supermemory production default) */
|
|
221
253
|
chunkOverlap?: number;
|
|
222
254
|
}
|
|
223
255
|
/**
|
|
@@ -246,11 +278,11 @@ interface RouterRequest {
|
|
|
246
278
|
messages: Message[];
|
|
247
279
|
/** Project ID for memory context */
|
|
248
280
|
projectId: string;
|
|
249
|
-
/** Model to use (
|
|
281
|
+
/** Model to use (default: 'gpt-4o-mini' - supermemory production default) */
|
|
250
282
|
model?: string;
|
|
251
|
-
/** Temperature for generation (0-2, default:
|
|
283
|
+
/** Temperature for generation (0-2, default: 0.7 - supermemory production default) */
|
|
252
284
|
temperature?: number;
|
|
253
|
-
/** Maximum tokens to generate */
|
|
285
|
+
/** Maximum tokens to generate (default: 2000 - supermemory production default) */
|
|
254
286
|
maxTokens?: number;
|
|
255
287
|
/** Whether to stream the response */
|
|
256
288
|
stream?: boolean;
|
|
@@ -612,9 +644,18 @@ declare class SearchResource {
|
|
|
612
644
|
private httpClient;
|
|
613
645
|
constructor(httpClient: HTTPClient);
|
|
614
646
|
/**
|
|
615
|
-
* Search memories
|
|
647
|
+
* Search memories using the unified /v1/search endpoint with hybrid retrieval.
|
|
648
|
+
*
|
|
649
|
+
* This uses the app's full retrieval pipeline with:
|
|
650
|
+
* - Vector similarity search
|
|
651
|
+
* - BM25 keyword search
|
|
652
|
+
* - Recency scoring
|
|
653
|
+
* - Graph connectivity (optional)
|
|
654
|
+
* - Entity expansion (optional)
|
|
655
|
+
* - LLM/Cross-encoder reranking (optional)
|
|
656
|
+
*
|
|
616
657
|
* @param request - Search request
|
|
617
|
-
* @returns Search results
|
|
658
|
+
* @returns Search results with memory pack structure
|
|
618
659
|
*/
|
|
619
660
|
search(request: SearchRequest): Promise<SearchResponse>;
|
|
620
661
|
}
|
|
@@ -637,6 +678,21 @@ declare class IngestResource {
|
|
|
637
678
|
* @returns Ingestion response with created memory IDs
|
|
638
679
|
*/
|
|
639
680
|
text(request: IngestTextRequest): Promise<IngestResponse>;
|
|
681
|
+
/**
|
|
682
|
+
* Ingest content from a URL
|
|
683
|
+
* @param url - URL to ingest from
|
|
684
|
+
* @param projectId - Project ID
|
|
685
|
+
* @param metadata - Optional metadata
|
|
686
|
+
* @returns Ingestion response with job details
|
|
687
|
+
*/
|
|
688
|
+
url(url: string, projectId: string, metadata?: Record<string, any>): Promise<IngestResponse>;
|
|
689
|
+
/**
|
|
690
|
+
* Get the status of an ingestion job
|
|
691
|
+
* @param jobId - Job ID returned from ingest
|
|
692
|
+
* @param projectId - Project ID
|
|
693
|
+
* @returns Job status information
|
|
694
|
+
*/
|
|
695
|
+
getJob(jobId: string, projectId: string): Promise<any>;
|
|
640
696
|
}
|
|
641
697
|
|
|
642
698
|
/**
|
package/dist/index.js
CHANGED
|
@@ -220,9 +220,18 @@ var init_search = __esm({
|
|
|
220
220
|
this.httpClient = httpClient;
|
|
221
221
|
}
|
|
222
222
|
/**
|
|
223
|
-
* Search memories
|
|
223
|
+
* Search memories using the unified /v1/search endpoint with hybrid retrieval.
|
|
224
|
+
*
|
|
225
|
+
* This uses the app's full retrieval pipeline with:
|
|
226
|
+
* - Vector similarity search
|
|
227
|
+
* - BM25 keyword search
|
|
228
|
+
* - Recency scoring
|
|
229
|
+
* - Graph connectivity (optional)
|
|
230
|
+
* - Entity expansion (optional)
|
|
231
|
+
* - LLM/Cross-encoder reranking (optional)
|
|
232
|
+
*
|
|
224
233
|
* @param request - Search request
|
|
225
|
-
* @returns Search results
|
|
234
|
+
* @returns Search results with memory pack structure
|
|
226
235
|
*/
|
|
227
236
|
async search(request) {
|
|
228
237
|
if (!request.query || request.query.trim().length === 0) {
|
|
@@ -237,24 +246,36 @@ var init_search = __esm({
|
|
|
237
246
|
[{ field: "projectId", message: "Project ID is required" }]
|
|
238
247
|
);
|
|
239
248
|
}
|
|
240
|
-
const
|
|
241
|
-
|
|
242
|
-
|
|
249
|
+
const body = {
|
|
250
|
+
query: request.query,
|
|
251
|
+
project_id: request.projectId,
|
|
252
|
+
include_text_format: true
|
|
243
253
|
};
|
|
244
254
|
if (request.limit !== void 0) {
|
|
245
|
-
|
|
246
|
-
}
|
|
247
|
-
if (request.threshold !== void 0) {
|
|
248
|
-
query.threshold = request.threshold.toString();
|
|
249
|
-
}
|
|
250
|
-
if (request.filter) {
|
|
251
|
-
query.filter = JSON.stringify(request.filter);
|
|
255
|
+
body.limit = request.limit;
|
|
252
256
|
}
|
|
253
|
-
|
|
254
|
-
|
|
257
|
+
body.rerank_strategy = request.rerankingStrategy || "cross-encoder";
|
|
258
|
+
const response = await this.httpClient.request({
|
|
259
|
+
method: "POST",
|
|
255
260
|
path: "/v1/search",
|
|
256
|
-
|
|
261
|
+
body
|
|
257
262
|
});
|
|
263
|
+
const memoryPack = response.memory_pack || {};
|
|
264
|
+
const results = [];
|
|
265
|
+
for (const memoryType of ["facts", "preferences", "entities", "sources"]) {
|
|
266
|
+
const items = memoryPack[memoryType] || [];
|
|
267
|
+
for (const item of items) {
|
|
268
|
+
results.push({
|
|
269
|
+
memory: item,
|
|
270
|
+
score: item.score || 1,
|
|
271
|
+
highlights: item.highlights || []
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return {
|
|
276
|
+
results,
|
|
277
|
+
total: results.length
|
|
278
|
+
};
|
|
258
279
|
}
|
|
259
280
|
};
|
|
260
281
|
}
|
|
@@ -292,18 +313,15 @@ var init_ingest = __esm({
|
|
|
292
313
|
[{ field: "projectId", message: "Project ID is required" }]
|
|
293
314
|
);
|
|
294
315
|
}
|
|
295
|
-
const body = {
|
|
296
|
-
projectId: request.projectId,
|
|
297
|
-
metadata: request.metadata,
|
|
298
|
-
chunkSize: request.chunkSize,
|
|
299
|
-
chunkOverlap: request.chunkOverlap,
|
|
300
|
-
// In a real implementation, you'd convert the file to base64 or use FormData
|
|
301
|
-
file: request.file
|
|
302
|
-
};
|
|
303
316
|
return this.httpClient.request({
|
|
304
317
|
method: "POST",
|
|
305
|
-
path: "/v1/ingest
|
|
306
|
-
body
|
|
318
|
+
path: "/v1/ingest",
|
|
319
|
+
body: {
|
|
320
|
+
type: "pdf",
|
|
321
|
+
projectId: request.projectId,
|
|
322
|
+
metadata: request.metadata || {},
|
|
323
|
+
file: request.file
|
|
324
|
+
}
|
|
307
325
|
});
|
|
308
326
|
}
|
|
309
327
|
/**
|
|
@@ -326,9 +344,71 @@ var init_ingest = __esm({
|
|
|
326
344
|
}
|
|
327
345
|
return this.httpClient.request({
|
|
328
346
|
method: "POST",
|
|
329
|
-
path: "/v1/ingest
|
|
330
|
-
body:
|
|
347
|
+
path: "/v1/ingest",
|
|
348
|
+
body: {
|
|
349
|
+
type: "text",
|
|
350
|
+
content: request.text,
|
|
351
|
+
projectId: request.projectId,
|
|
352
|
+
metadata: request.metadata || {}
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Ingest content from a URL
|
|
358
|
+
* @param url - URL to ingest from
|
|
359
|
+
* @param projectId - Project ID
|
|
360
|
+
* @param metadata - Optional metadata
|
|
361
|
+
* @returns Ingestion response with job details
|
|
362
|
+
*/
|
|
363
|
+
async url(url, projectId, metadata) {
|
|
364
|
+
if (!url || url.trim().length === 0) {
|
|
365
|
+
throw new ValidationError(
|
|
366
|
+
"URL cannot be empty",
|
|
367
|
+
[{ field: "url", message: "URL is required and cannot be empty" }]
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
if (!projectId || projectId.trim().length === 0) {
|
|
371
|
+
throw new ValidationError(
|
|
372
|
+
"Project ID is required",
|
|
373
|
+
[{ field: "projectId", message: "Project ID is required" }]
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
return this.httpClient.request({
|
|
377
|
+
method: "POST",
|
|
378
|
+
path: "/v1/ingest",
|
|
379
|
+
body: {
|
|
380
|
+
type: "url",
|
|
381
|
+
url,
|
|
382
|
+
projectId,
|
|
383
|
+
metadata: metadata || {}
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Get the status of an ingestion job
|
|
389
|
+
* @param jobId - Job ID returned from ingest
|
|
390
|
+
* @param projectId - Project ID
|
|
391
|
+
* @returns Job status information
|
|
392
|
+
*/
|
|
393
|
+
async getJob(jobId, projectId) {
|
|
394
|
+
if (!jobId || jobId.trim().length === 0) {
|
|
395
|
+
throw new ValidationError(
|
|
396
|
+
"Job ID is required",
|
|
397
|
+
[{ field: "jobId", message: "Job ID is required" }]
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
if (!projectId || projectId.trim().length === 0) {
|
|
401
|
+
throw new ValidationError(
|
|
402
|
+
"Project ID is required",
|
|
403
|
+
[{ field: "projectId", message: "Project ID is required" }]
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
const response = await this.httpClient.request({
|
|
407
|
+
method: "GET",
|
|
408
|
+
path: `/v1/jobs/${jobId}`,
|
|
409
|
+
query: { projectId }
|
|
331
410
|
});
|
|
411
|
+
return response.data || response;
|
|
332
412
|
}
|
|
333
413
|
};
|
|
334
414
|
}
|
package/package.json
CHANGED
package/src/resources/ingest.ts
CHANGED
|
@@ -29,21 +29,16 @@ export class IngestResource {
|
|
|
29
29
|
);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
//
|
|
33
|
-
// This is a simplified implementation - in production, you'd handle multipart/form-data properly
|
|
34
|
-
const body = {
|
|
35
|
-
projectId: request.projectId,
|
|
36
|
-
metadata: request.metadata,
|
|
37
|
-
chunkSize: request.chunkSize,
|
|
38
|
-
chunkOverlap: request.chunkOverlap,
|
|
39
|
-
// In a real implementation, you'd convert the file to base64 or use FormData
|
|
40
|
-
file: request.file,
|
|
41
|
-
};
|
|
42
|
-
|
|
32
|
+
// Use unified /v1/ingest endpoint matching the app
|
|
43
33
|
return this.httpClient.request<IngestResponse>({
|
|
44
34
|
method: 'POST',
|
|
45
|
-
path: '/v1/ingest
|
|
46
|
-
body
|
|
35
|
+
path: '/v1/ingest',
|
|
36
|
+
body: {
|
|
37
|
+
type: 'pdf',
|
|
38
|
+
projectId: request.projectId,
|
|
39
|
+
metadata: request.metadata || {},
|
|
40
|
+
file: request.file,
|
|
41
|
+
},
|
|
47
42
|
});
|
|
48
43
|
}
|
|
49
44
|
|
|
@@ -68,10 +63,82 @@ export class IngestResource {
|
|
|
68
63
|
);
|
|
69
64
|
}
|
|
70
65
|
|
|
66
|
+
// Use unified /v1/ingest endpoint matching the app
|
|
71
67
|
return this.httpClient.request<IngestResponse>({
|
|
72
68
|
method: 'POST',
|
|
73
|
-
path: '/v1/ingest
|
|
74
|
-
body:
|
|
69
|
+
path: '/v1/ingest',
|
|
70
|
+
body: {
|
|
71
|
+
type: 'text',
|
|
72
|
+
content: request.text,
|
|
73
|
+
projectId: request.projectId,
|
|
74
|
+
metadata: request.metadata || {},
|
|
75
|
+
},
|
|
75
76
|
});
|
|
76
77
|
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Ingest content from a URL
|
|
81
|
+
* @param url - URL to ingest from
|
|
82
|
+
* @param projectId - Project ID
|
|
83
|
+
* @param metadata - Optional metadata
|
|
84
|
+
* @returns Ingestion response with job details
|
|
85
|
+
*/
|
|
86
|
+
async url(url: string, projectId: string, metadata?: Record<string, any>): Promise<IngestResponse> {
|
|
87
|
+
// Validate request
|
|
88
|
+
if (!url || url.trim().length === 0) {
|
|
89
|
+
throw new ValidationError(
|
|
90
|
+
'URL cannot be empty',
|
|
91
|
+
[{ field: 'url', message: 'URL is required and cannot be empty' }]
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (!projectId || projectId.trim().length === 0) {
|
|
96
|
+
throw new ValidationError(
|
|
97
|
+
'Project ID is required',
|
|
98
|
+
[{ field: 'projectId', message: 'Project ID is required' }]
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Use unified /v1/ingest endpoint matching the app
|
|
103
|
+
return this.httpClient.request<IngestResponse>({
|
|
104
|
+
method: 'POST',
|
|
105
|
+
path: '/v1/ingest',
|
|
106
|
+
body: {
|
|
107
|
+
type: 'url',
|
|
108
|
+
url,
|
|
109
|
+
projectId,
|
|
110
|
+
metadata: metadata || {},
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Get the status of an ingestion job
|
|
117
|
+
* @param jobId - Job ID returned from ingest
|
|
118
|
+
* @param projectId - Project ID
|
|
119
|
+
* @returns Job status information
|
|
120
|
+
*/
|
|
121
|
+
async getJob(jobId: string, projectId: string): Promise<any> {
|
|
122
|
+
if (!jobId || jobId.trim().length === 0) {
|
|
123
|
+
throw new ValidationError(
|
|
124
|
+
'Job ID is required',
|
|
125
|
+
[{ field: 'jobId', message: 'Job ID is required' }]
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (!projectId || projectId.trim().length === 0) {
|
|
130
|
+
throw new ValidationError(
|
|
131
|
+
'Project ID is required',
|
|
132
|
+
[{ field: 'projectId', message: 'Project ID is required' }]
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const response = await this.httpClient.request<any>({
|
|
137
|
+
method: 'GET',
|
|
138
|
+
path: `/v1/jobs/${jobId}`,
|
|
139
|
+
query: { projectId },
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
return response.data || response;
|
|
143
|
+
}
|
|
77
144
|
}
|
package/src/resources/search.ts
CHANGED
|
@@ -9,9 +9,18 @@ export class SearchResource {
|
|
|
9
9
|
constructor(private httpClient: HTTPClient) {}
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* Search memories
|
|
12
|
+
* Search memories using the unified /v1/search endpoint with hybrid retrieval.
|
|
13
|
+
*
|
|
14
|
+
* This uses the app's full retrieval pipeline with:
|
|
15
|
+
* - Vector similarity search
|
|
16
|
+
* - BM25 keyword search
|
|
17
|
+
* - Recency scoring
|
|
18
|
+
* - Graph connectivity (optional)
|
|
19
|
+
* - Entity expansion (optional)
|
|
20
|
+
* - LLM/Cross-encoder reranking (optional)
|
|
21
|
+
*
|
|
13
22
|
* @param request - Search request
|
|
14
|
-
* @returns Search results
|
|
23
|
+
* @returns Search results with memory pack structure
|
|
15
24
|
*/
|
|
16
25
|
async search(request: SearchRequest): Promise<SearchResponse> {
|
|
17
26
|
// Validate request
|
|
@@ -29,27 +38,46 @@ export class SearchResource {
|
|
|
29
38
|
);
|
|
30
39
|
}
|
|
31
40
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
41
|
+
// Build request body matching the app's POST /v1/search endpoint
|
|
42
|
+
const body: any = {
|
|
43
|
+
query: request.query,
|
|
44
|
+
project_id: request.projectId,
|
|
45
|
+
include_text_format: true,
|
|
35
46
|
};
|
|
36
47
|
|
|
37
48
|
if (request.limit !== undefined) {
|
|
38
|
-
|
|
49
|
+
body.limit = request.limit;
|
|
39
50
|
}
|
|
40
51
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (request.filter) {
|
|
46
|
-
query.filter = JSON.stringify(request.filter);
|
|
47
|
-
}
|
|
52
|
+
// Use rerank_strategy to match app's parameter name
|
|
53
|
+
body.rerank_strategy = request.rerankingStrategy || 'cross-encoder';
|
|
48
54
|
|
|
49
|
-
|
|
50
|
-
|
|
55
|
+
// Use POST method to match the app's endpoint
|
|
56
|
+
const response = await this.httpClient.request<any>({
|
|
57
|
+
method: 'POST',
|
|
51
58
|
path: '/v1/search',
|
|
52
|
-
|
|
59
|
+
body,
|
|
53
60
|
});
|
|
61
|
+
|
|
62
|
+
// Parse response from memory_pack format
|
|
63
|
+
const memoryPack = response.memory_pack || {};
|
|
64
|
+
const results = [];
|
|
65
|
+
|
|
66
|
+
// Extract memories from memory pack structure
|
|
67
|
+
for (const memoryType of ['facts', 'preferences', 'entities', 'sources']) {
|
|
68
|
+
const items = memoryPack[memoryType] || [];
|
|
69
|
+
for (const item of items) {
|
|
70
|
+
results.push({
|
|
71
|
+
memory: item,
|
|
72
|
+
score: item.score || 1.0,
|
|
73
|
+
highlights: item.highlights || [],
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
results,
|
|
80
|
+
total: results.length,
|
|
81
|
+
};
|
|
54
82
|
}
|
|
55
83
|
}
|
package/src/types.ts
CHANGED
|
@@ -60,12 +60,30 @@ export interface SearchRequest {
|
|
|
60
60
|
query: string;
|
|
61
61
|
/** Project ID to search in */
|
|
62
62
|
projectId: string;
|
|
63
|
-
/** Maximum number of results to return (default: 10) */
|
|
63
|
+
/** Maximum number of results to return (default: 10 - supermemory production default) */
|
|
64
64
|
limit?: number;
|
|
65
65
|
/** Filter criteria for search */
|
|
66
66
|
filter?: Record<string, any>;
|
|
67
|
-
/** Minimum relevance score threshold (0-1) */
|
|
67
|
+
/** Minimum relevance score threshold (0-1, default: 0.6 - supermemory production default for broad recall) */
|
|
68
68
|
threshold?: number;
|
|
69
|
+
/** Enable query rewriting (default: false - adds ~400ms latency) */
|
|
70
|
+
enableQueryRewriting?: boolean;
|
|
71
|
+
/** Enable entity expansion search (default: false) */
|
|
72
|
+
enableEntityExpansion?: boolean;
|
|
73
|
+
/** Enable graph connectivity search (default: false) */
|
|
74
|
+
enableGraphConnectivity?: boolean;
|
|
75
|
+
/** Enable semantic deduplication (default: false) */
|
|
76
|
+
enableSemanticDedup?: boolean;
|
|
77
|
+
/** Reranking strategy: 'none', 'cross-encoder', 'llm' (default: 'none' - adds latency) */
|
|
78
|
+
rerankingStrategy?: 'none' | 'cross-encoder' | 'llm';
|
|
79
|
+
/** Custom fusion weights for multi-method retrieval */
|
|
80
|
+
fusionWeights?: {
|
|
81
|
+
vector?: number;
|
|
82
|
+
bm25?: number;
|
|
83
|
+
recency?: number;
|
|
84
|
+
entity?: number;
|
|
85
|
+
graph?: number;
|
|
86
|
+
};
|
|
69
87
|
}
|
|
70
88
|
|
|
71
89
|
/**
|
|
@@ -78,6 +96,20 @@ export interface SearchResult {
|
|
|
78
96
|
score: number;
|
|
79
97
|
/** Highlighted text snippets */
|
|
80
98
|
highlights?: string[];
|
|
99
|
+
/** Score breakdown by retrieval method */
|
|
100
|
+
scoreBreakdown?: {
|
|
101
|
+
vectorScore?: number;
|
|
102
|
+
bm25Score?: number;
|
|
103
|
+
recencyScore?: number;
|
|
104
|
+
entityScore?: number;
|
|
105
|
+
graphScore?: number;
|
|
106
|
+
};
|
|
107
|
+
/** Connected memories (if graph enhancement enabled) */
|
|
108
|
+
connections?: Array<{
|
|
109
|
+
memoryId: string;
|
|
110
|
+
connectionType: 'updates' | 'extends' | 'derives' | 'similarity';
|
|
111
|
+
connectionStrength: number;
|
|
112
|
+
}>;
|
|
81
113
|
}
|
|
82
114
|
|
|
83
115
|
/**
|
|
@@ -100,9 +132,9 @@ export interface IngestFileRequest {
|
|
|
100
132
|
projectId: string;
|
|
101
133
|
/** Optional metadata to associate with ingested memories */
|
|
102
134
|
metadata?: Record<string, any>;
|
|
103
|
-
/** Chunk size for splitting the file (default:
|
|
135
|
+
/** Chunk size for splitting the file (default: 512 tokens - supermemory production default) */
|
|
104
136
|
chunkSize?: number;
|
|
105
|
-
/** Overlap between chunks (default:
|
|
137
|
+
/** Overlap between chunks (default: 10% - supermemory production default) */
|
|
106
138
|
chunkOverlap?: number;
|
|
107
139
|
}
|
|
108
140
|
|
|
@@ -116,9 +148,9 @@ export interface IngestTextRequest {
|
|
|
116
148
|
projectId: string;
|
|
117
149
|
/** Optional metadata to associate with ingested memories */
|
|
118
150
|
metadata?: Record<string, any>;
|
|
119
|
-
/** Chunk size for splitting the text (default:
|
|
151
|
+
/** Chunk size for splitting the text (default: 512 tokens - supermemory production default) */
|
|
120
152
|
chunkSize?: number;
|
|
121
|
-
/** Overlap between chunks (default:
|
|
153
|
+
/** Overlap between chunks (default: 10% - supermemory production default) */
|
|
122
154
|
chunkOverlap?: number;
|
|
123
155
|
}
|
|
124
156
|
|
|
@@ -150,11 +182,11 @@ export interface RouterRequest {
|
|
|
150
182
|
messages: Message[];
|
|
151
183
|
/** Project ID for memory context */
|
|
152
184
|
projectId: string;
|
|
153
|
-
/** Model to use (
|
|
185
|
+
/** Model to use (default: 'gpt-4o-mini' - supermemory production default) */
|
|
154
186
|
model?: string;
|
|
155
|
-
/** Temperature for generation (0-2, default:
|
|
187
|
+
/** Temperature for generation (0-2, default: 0.7 - supermemory production default) */
|
|
156
188
|
temperature?: number;
|
|
157
|
-
/** Maximum tokens to generate */
|
|
189
|
+
/** Maximum tokens to generate (default: 2000 - supermemory production default) */
|
|
158
190
|
maxTokens?: number;
|
|
159
191
|
/** Whether to stream the response */
|
|
160
192
|
stream?: boolean;
|