@memorylayerai/sdk 0.4.0 → 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/dist/index.cjs +107 -45
- package/dist/index.d.cts +37 -13
- package/dist/index.d.ts +37 -13
- package/dist/index.js +107 -45
- package/package.json +1 -1
- package/src/resources/ingest.ts +82 -15
- package/src/resources/search.ts +42 -39
- package/src/types.ts +11 -11
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,42 +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
|
-
|
|
256
|
-
|
|
257
|
-
if (request.enableEntityExpansion !== void 0) {
|
|
258
|
-
query.enableEntityExpansion = request.enableEntityExpansion.toString();
|
|
259
|
-
}
|
|
260
|
-
if (request.enableGraphConnectivity !== void 0) {
|
|
261
|
-
query.enableGraphConnectivity = request.enableGraphConnectivity.toString();
|
|
262
|
-
}
|
|
263
|
-
if (request.enableSemanticDedup !== void 0) {
|
|
264
|
-
query.enableSemanticDedup = request.enableSemanticDedup.toString();
|
|
265
|
-
}
|
|
266
|
-
if (request.rerankingStrategy) {
|
|
267
|
-
query.rerankingStrategy = request.rerankingStrategy;
|
|
268
|
-
}
|
|
269
|
-
if (request.fusionWeights) {
|
|
270
|
-
query.fusionWeights = JSON.stringify(request.fusionWeights);
|
|
271
|
-
}
|
|
272
|
-
return this.httpClient.request({
|
|
273
|
-
method: "GET",
|
|
258
|
+
body.rerank_strategy = request.rerankingStrategy || "cross-encoder";
|
|
259
|
+
const response = await this.httpClient.request({
|
|
260
|
+
method: "POST",
|
|
274
261
|
path: "/v1/search",
|
|
275
|
-
|
|
262
|
+
body
|
|
276
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
|
+
};
|
|
277
280
|
}
|
|
278
281
|
};
|
|
279
282
|
}
|
|
@@ -311,18 +314,15 @@ var init_ingest = __esm({
|
|
|
311
314
|
[{ field: "projectId", message: "Project ID is required" }]
|
|
312
315
|
);
|
|
313
316
|
}
|
|
314
|
-
const body = {
|
|
315
|
-
projectId: request.projectId,
|
|
316
|
-
metadata: request.metadata,
|
|
317
|
-
chunkSize: request.chunkSize,
|
|
318
|
-
chunkOverlap: request.chunkOverlap,
|
|
319
|
-
// In a real implementation, you'd convert the file to base64 or use FormData
|
|
320
|
-
file: request.file
|
|
321
|
-
};
|
|
322
317
|
return this.httpClient.request({
|
|
323
318
|
method: "POST",
|
|
324
|
-
path: "/v1/ingest
|
|
325
|
-
body
|
|
319
|
+
path: "/v1/ingest",
|
|
320
|
+
body: {
|
|
321
|
+
type: "pdf",
|
|
322
|
+
projectId: request.projectId,
|
|
323
|
+
metadata: request.metadata || {},
|
|
324
|
+
file: request.file
|
|
325
|
+
}
|
|
326
326
|
});
|
|
327
327
|
}
|
|
328
328
|
/**
|
|
@@ -345,9 +345,71 @@ var init_ingest = __esm({
|
|
|
345
345
|
}
|
|
346
346
|
return this.httpClient.request({
|
|
347
347
|
method: "POST",
|
|
348
|
-
path: "/v1/ingest
|
|
349
|
-
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 }
|
|
350
411
|
});
|
|
412
|
+
return response.data || response;
|
|
351
413
|
}
|
|
352
414
|
};
|
|
353
415
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -163,13 +163,13 @@ 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:
|
|
172
|
+
/** Enable query rewriting (default: false - adds ~400ms latency) */
|
|
173
173
|
enableQueryRewriting?: boolean;
|
|
174
174
|
/** Enable entity expansion search (default: false) */
|
|
175
175
|
enableEntityExpansion?: boolean;
|
|
@@ -177,7 +177,7 @@ interface SearchRequest {
|
|
|
177
177
|
enableGraphConnectivity?: boolean;
|
|
178
178
|
/** Enable semantic deduplication (default: false) */
|
|
179
179
|
enableSemanticDedup?: boolean;
|
|
180
|
-
/** Reranking strategy: 'none', 'cross-encoder', 'llm' (default: 'none') */
|
|
180
|
+
/** Reranking strategy: 'none', 'cross-encoder', 'llm' (default: 'none' - adds latency) */
|
|
181
181
|
rerankingStrategy?: 'none' | 'cross-encoder' | 'llm';
|
|
182
182
|
/** Custom fusion weights for multi-method retrieval */
|
|
183
183
|
fusionWeights?: {
|
|
@@ -232,9 +232,9 @@ interface IngestFileRequest {
|
|
|
232
232
|
projectId: string;
|
|
233
233
|
/** Optional metadata to associate with ingested memories */
|
|
234
234
|
metadata?: Record<string, any>;
|
|
235
|
-
/** Chunk size for splitting the file (default:
|
|
235
|
+
/** Chunk size for splitting the file (default: 512 tokens - supermemory production default) */
|
|
236
236
|
chunkSize?: number;
|
|
237
|
-
/** Overlap between chunks (default:
|
|
237
|
+
/** Overlap between chunks (default: 10% - supermemory production default) */
|
|
238
238
|
chunkOverlap?: number;
|
|
239
239
|
}
|
|
240
240
|
/**
|
|
@@ -247,9 +247,9 @@ interface IngestTextRequest {
|
|
|
247
247
|
projectId: string;
|
|
248
248
|
/** Optional metadata to associate with ingested memories */
|
|
249
249
|
metadata?: Record<string, any>;
|
|
250
|
-
/** Chunk size for splitting the text (default:
|
|
250
|
+
/** Chunk size for splitting the text (default: 512 tokens - supermemory production default) */
|
|
251
251
|
chunkSize?: number;
|
|
252
|
-
/** Overlap between chunks (default:
|
|
252
|
+
/** Overlap between chunks (default: 10% - supermemory production default) */
|
|
253
253
|
chunkOverlap?: number;
|
|
254
254
|
}
|
|
255
255
|
/**
|
|
@@ -278,11 +278,11 @@ interface RouterRequest {
|
|
|
278
278
|
messages: Message[];
|
|
279
279
|
/** Project ID for memory context */
|
|
280
280
|
projectId: string;
|
|
281
|
-
/** Model to use (
|
|
281
|
+
/** Model to use (default: 'gpt-4o-mini' - supermemory production default) */
|
|
282
282
|
model?: string;
|
|
283
|
-
/** Temperature for generation (0-2, default:
|
|
283
|
+
/** Temperature for generation (0-2, default: 0.7 - supermemory production default) */
|
|
284
284
|
temperature?: number;
|
|
285
|
-
/** Maximum tokens to generate */
|
|
285
|
+
/** Maximum tokens to generate (default: 2000 - supermemory production default) */
|
|
286
286
|
maxTokens?: number;
|
|
287
287
|
/** Whether to stream the response */
|
|
288
288
|
stream?: boolean;
|
|
@@ -644,9 +644,18 @@ declare class SearchResource {
|
|
|
644
644
|
private httpClient;
|
|
645
645
|
constructor(httpClient: HTTPClient);
|
|
646
646
|
/**
|
|
647
|
-
* 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
|
+
*
|
|
648
657
|
* @param request - Search request
|
|
649
|
-
* @returns Search results
|
|
658
|
+
* @returns Search results with memory pack structure
|
|
650
659
|
*/
|
|
651
660
|
search(request: SearchRequest): Promise<SearchResponse>;
|
|
652
661
|
}
|
|
@@ -669,6 +678,21 @@ declare class IngestResource {
|
|
|
669
678
|
* @returns Ingestion response with created memory IDs
|
|
670
679
|
*/
|
|
671
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>;
|
|
672
696
|
}
|
|
673
697
|
|
|
674
698
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -163,13 +163,13 @@ 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:
|
|
172
|
+
/** Enable query rewriting (default: false - adds ~400ms latency) */
|
|
173
173
|
enableQueryRewriting?: boolean;
|
|
174
174
|
/** Enable entity expansion search (default: false) */
|
|
175
175
|
enableEntityExpansion?: boolean;
|
|
@@ -177,7 +177,7 @@ interface SearchRequest {
|
|
|
177
177
|
enableGraphConnectivity?: boolean;
|
|
178
178
|
/** Enable semantic deduplication (default: false) */
|
|
179
179
|
enableSemanticDedup?: boolean;
|
|
180
|
-
/** Reranking strategy: 'none', 'cross-encoder', 'llm' (default: 'none') */
|
|
180
|
+
/** Reranking strategy: 'none', 'cross-encoder', 'llm' (default: 'none' - adds latency) */
|
|
181
181
|
rerankingStrategy?: 'none' | 'cross-encoder' | 'llm';
|
|
182
182
|
/** Custom fusion weights for multi-method retrieval */
|
|
183
183
|
fusionWeights?: {
|
|
@@ -232,9 +232,9 @@ interface IngestFileRequest {
|
|
|
232
232
|
projectId: string;
|
|
233
233
|
/** Optional metadata to associate with ingested memories */
|
|
234
234
|
metadata?: Record<string, any>;
|
|
235
|
-
/** Chunk size for splitting the file (default:
|
|
235
|
+
/** Chunk size for splitting the file (default: 512 tokens - supermemory production default) */
|
|
236
236
|
chunkSize?: number;
|
|
237
|
-
/** Overlap between chunks (default:
|
|
237
|
+
/** Overlap between chunks (default: 10% - supermemory production default) */
|
|
238
238
|
chunkOverlap?: number;
|
|
239
239
|
}
|
|
240
240
|
/**
|
|
@@ -247,9 +247,9 @@ interface IngestTextRequest {
|
|
|
247
247
|
projectId: string;
|
|
248
248
|
/** Optional metadata to associate with ingested memories */
|
|
249
249
|
metadata?: Record<string, any>;
|
|
250
|
-
/** Chunk size for splitting the text (default:
|
|
250
|
+
/** Chunk size for splitting the text (default: 512 tokens - supermemory production default) */
|
|
251
251
|
chunkSize?: number;
|
|
252
|
-
/** Overlap between chunks (default:
|
|
252
|
+
/** Overlap between chunks (default: 10% - supermemory production default) */
|
|
253
253
|
chunkOverlap?: number;
|
|
254
254
|
}
|
|
255
255
|
/**
|
|
@@ -278,11 +278,11 @@ interface RouterRequest {
|
|
|
278
278
|
messages: Message[];
|
|
279
279
|
/** Project ID for memory context */
|
|
280
280
|
projectId: string;
|
|
281
|
-
/** Model to use (
|
|
281
|
+
/** Model to use (default: 'gpt-4o-mini' - supermemory production default) */
|
|
282
282
|
model?: string;
|
|
283
|
-
/** Temperature for generation (0-2, default:
|
|
283
|
+
/** Temperature for generation (0-2, default: 0.7 - supermemory production default) */
|
|
284
284
|
temperature?: number;
|
|
285
|
-
/** Maximum tokens to generate */
|
|
285
|
+
/** Maximum tokens to generate (default: 2000 - supermemory production default) */
|
|
286
286
|
maxTokens?: number;
|
|
287
287
|
/** Whether to stream the response */
|
|
288
288
|
stream?: boolean;
|
|
@@ -644,9 +644,18 @@ declare class SearchResource {
|
|
|
644
644
|
private httpClient;
|
|
645
645
|
constructor(httpClient: HTTPClient);
|
|
646
646
|
/**
|
|
647
|
-
* 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
|
+
*
|
|
648
657
|
* @param request - Search request
|
|
649
|
-
* @returns Search results
|
|
658
|
+
* @returns Search results with memory pack structure
|
|
650
659
|
*/
|
|
651
660
|
search(request: SearchRequest): Promise<SearchResponse>;
|
|
652
661
|
}
|
|
@@ -669,6 +678,21 @@ declare class IngestResource {
|
|
|
669
678
|
* @returns Ingestion response with created memory IDs
|
|
670
679
|
*/
|
|
671
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>;
|
|
672
696
|
}
|
|
673
697
|
|
|
674
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,42 +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
|
-
|
|
255
|
-
|
|
256
|
-
if (request.enableEntityExpansion !== void 0) {
|
|
257
|
-
query.enableEntityExpansion = request.enableEntityExpansion.toString();
|
|
258
|
-
}
|
|
259
|
-
if (request.enableGraphConnectivity !== void 0) {
|
|
260
|
-
query.enableGraphConnectivity = request.enableGraphConnectivity.toString();
|
|
261
|
-
}
|
|
262
|
-
if (request.enableSemanticDedup !== void 0) {
|
|
263
|
-
query.enableSemanticDedup = request.enableSemanticDedup.toString();
|
|
264
|
-
}
|
|
265
|
-
if (request.rerankingStrategy) {
|
|
266
|
-
query.rerankingStrategy = request.rerankingStrategy;
|
|
267
|
-
}
|
|
268
|
-
if (request.fusionWeights) {
|
|
269
|
-
query.fusionWeights = JSON.stringify(request.fusionWeights);
|
|
270
|
-
}
|
|
271
|
-
return this.httpClient.request({
|
|
272
|
-
method: "GET",
|
|
257
|
+
body.rerank_strategy = request.rerankingStrategy || "cross-encoder";
|
|
258
|
+
const response = await this.httpClient.request({
|
|
259
|
+
method: "POST",
|
|
273
260
|
path: "/v1/search",
|
|
274
|
-
|
|
261
|
+
body
|
|
275
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
|
+
};
|
|
276
279
|
}
|
|
277
280
|
};
|
|
278
281
|
}
|
|
@@ -310,18 +313,15 @@ var init_ingest = __esm({
|
|
|
310
313
|
[{ field: "projectId", message: "Project ID is required" }]
|
|
311
314
|
);
|
|
312
315
|
}
|
|
313
|
-
const body = {
|
|
314
|
-
projectId: request.projectId,
|
|
315
|
-
metadata: request.metadata,
|
|
316
|
-
chunkSize: request.chunkSize,
|
|
317
|
-
chunkOverlap: request.chunkOverlap,
|
|
318
|
-
// In a real implementation, you'd convert the file to base64 or use FormData
|
|
319
|
-
file: request.file
|
|
320
|
-
};
|
|
321
316
|
return this.httpClient.request({
|
|
322
317
|
method: "POST",
|
|
323
|
-
path: "/v1/ingest
|
|
324
|
-
body
|
|
318
|
+
path: "/v1/ingest",
|
|
319
|
+
body: {
|
|
320
|
+
type: "pdf",
|
|
321
|
+
projectId: request.projectId,
|
|
322
|
+
metadata: request.metadata || {},
|
|
323
|
+
file: request.file
|
|
324
|
+
}
|
|
325
325
|
});
|
|
326
326
|
}
|
|
327
327
|
/**
|
|
@@ -344,9 +344,71 @@ var init_ingest = __esm({
|
|
|
344
344
|
}
|
|
345
345
|
return this.httpClient.request({
|
|
346
346
|
method: "POST",
|
|
347
|
-
path: "/v1/ingest
|
|
348
|
-
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 }
|
|
349
410
|
});
|
|
411
|
+
return response.data || response;
|
|
350
412
|
}
|
|
351
413
|
};
|
|
352
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,52 +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
|
-
}
|
|
48
|
-
|
|
49
|
-
// New advanced retrieval options
|
|
50
|
-
if (request.enableQueryRewriting !== undefined) {
|
|
51
|
-
query.enableQueryRewriting = request.enableQueryRewriting.toString();
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (request.enableEntityExpansion !== undefined) {
|
|
55
|
-
query.enableEntityExpansion = request.enableEntityExpansion.toString();
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (request.enableGraphConnectivity !== undefined) {
|
|
59
|
-
query.enableGraphConnectivity = request.enableGraphConnectivity.toString();
|
|
60
|
-
}
|
|
52
|
+
// Use rerank_strategy to match app's parameter name
|
|
53
|
+
body.rerank_strategy = request.rerankingStrategy || 'cross-encoder';
|
|
61
54
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
55
|
+
// Use POST method to match the app's endpoint
|
|
56
|
+
const response = await this.httpClient.request<any>({
|
|
57
|
+
method: 'POST',
|
|
58
|
+
path: '/v1/search',
|
|
59
|
+
body,
|
|
60
|
+
});
|
|
65
61
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
62
|
+
// Parse response from memory_pack format
|
|
63
|
+
const memoryPack = response.memory_pack || {};
|
|
64
|
+
const results = [];
|
|
69
65
|
|
|
70
|
-
|
|
71
|
-
|
|
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
|
+
}
|
|
72
76
|
}
|
|
73
77
|
|
|
74
|
-
return
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
});
|
|
78
|
+
return {
|
|
79
|
+
results,
|
|
80
|
+
total: results.length,
|
|
81
|
+
};
|
|
79
82
|
}
|
|
80
83
|
}
|
package/src/types.ts
CHANGED
|
@@ -60,13 +60,13 @@ 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:
|
|
69
|
+
/** Enable query rewriting (default: false - adds ~400ms latency) */
|
|
70
70
|
enableQueryRewriting?: boolean;
|
|
71
71
|
/** Enable entity expansion search (default: false) */
|
|
72
72
|
enableEntityExpansion?: boolean;
|
|
@@ -74,7 +74,7 @@ export interface SearchRequest {
|
|
|
74
74
|
enableGraphConnectivity?: boolean;
|
|
75
75
|
/** Enable semantic deduplication (default: false) */
|
|
76
76
|
enableSemanticDedup?: boolean;
|
|
77
|
-
/** Reranking strategy: 'none', 'cross-encoder', 'llm' (default: 'none') */
|
|
77
|
+
/** Reranking strategy: 'none', 'cross-encoder', 'llm' (default: 'none' - adds latency) */
|
|
78
78
|
rerankingStrategy?: 'none' | 'cross-encoder' | 'llm';
|
|
79
79
|
/** Custom fusion weights for multi-method retrieval */
|
|
80
80
|
fusionWeights?: {
|
|
@@ -132,9 +132,9 @@ export interface IngestFileRequest {
|
|
|
132
132
|
projectId: string;
|
|
133
133
|
/** Optional metadata to associate with ingested memories */
|
|
134
134
|
metadata?: Record<string, any>;
|
|
135
|
-
/** Chunk size for splitting the file (default:
|
|
135
|
+
/** Chunk size for splitting the file (default: 512 tokens - supermemory production default) */
|
|
136
136
|
chunkSize?: number;
|
|
137
|
-
/** Overlap between chunks (default:
|
|
137
|
+
/** Overlap between chunks (default: 10% - supermemory production default) */
|
|
138
138
|
chunkOverlap?: number;
|
|
139
139
|
}
|
|
140
140
|
|
|
@@ -148,9 +148,9 @@ export interface IngestTextRequest {
|
|
|
148
148
|
projectId: string;
|
|
149
149
|
/** Optional metadata to associate with ingested memories */
|
|
150
150
|
metadata?: Record<string, any>;
|
|
151
|
-
/** Chunk size for splitting the text (default:
|
|
151
|
+
/** Chunk size for splitting the text (default: 512 tokens - supermemory production default) */
|
|
152
152
|
chunkSize?: number;
|
|
153
|
-
/** Overlap between chunks (default:
|
|
153
|
+
/** Overlap between chunks (default: 10% - supermemory production default) */
|
|
154
154
|
chunkOverlap?: number;
|
|
155
155
|
}
|
|
156
156
|
|
|
@@ -182,11 +182,11 @@ export interface RouterRequest {
|
|
|
182
182
|
messages: Message[];
|
|
183
183
|
/** Project ID for memory context */
|
|
184
184
|
projectId: string;
|
|
185
|
-
/** Model to use (
|
|
185
|
+
/** Model to use (default: 'gpt-4o-mini' - supermemory production default) */
|
|
186
186
|
model?: string;
|
|
187
|
-
/** Temperature for generation (0-2, default:
|
|
187
|
+
/** Temperature for generation (0-2, default: 0.7 - supermemory production default) */
|
|
188
188
|
temperature?: number;
|
|
189
|
-
/** Maximum tokens to generate */
|
|
189
|
+
/** Maximum tokens to generate (default: 2000 - supermemory production default) */
|
|
190
190
|
maxTokens?: number;
|
|
191
191
|
/** Whether to stream the response */
|
|
192
192
|
stream?: boolean;
|