@memorylayerai/sdk 0.4.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +75 -0
- package/bun.lock +390 -0
- package/dist/index.cjs +107 -45
- package/dist/index.d.cts +74 -13
- package/dist/index.d.ts +74 -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 +50 -11
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
|
@@ -1,3 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model provider options for multi-provider support
|
|
3
|
+
* Allows overriding org-level settings at request time
|
|
4
|
+
*
|
|
5
|
+
* Supported providers:
|
|
6
|
+
* - 'openai': OpenAI GPT models and text-embedding models
|
|
7
|
+
* - 'google': Google Gemini models and text-embedding-004
|
|
8
|
+
* - 'anthropic': Anthropic Claude models (uses OpenAI embeddings for vector search)
|
|
9
|
+
*/
|
|
10
|
+
export type ModelProvider = 'openai' | 'google' | 'anthropic';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Model settings for request-level override
|
|
14
|
+
*/
|
|
15
|
+
export interface ModelSettings {
|
|
16
|
+
/** Model provider: 'openai', 'google', or 'anthropic' */
|
|
17
|
+
provider?: ModelProvider;
|
|
18
|
+
/**
|
|
19
|
+
* Embedding model to use:
|
|
20
|
+
* - OpenAI: 'text-embedding-3-small', 'text-embedding-3-large', 'text-embedding-ada-002'
|
|
21
|
+
* - Google: 'text-embedding-004'
|
|
22
|
+
* - Anthropic: Uses OpenAI embeddings (specify OpenAI model)
|
|
23
|
+
*/
|
|
24
|
+
embeddingModel?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Language model for extraction/generation:
|
|
27
|
+
* - OpenAI: 'gpt-4o', 'gpt-4o-mini', 'gpt-4-turbo', 'o1', 'o1-mini'
|
|
28
|
+
* - Google: 'gemini-2.5-flash', 'gemini-2.5-pro', 'gemini-2.0-flash'
|
|
29
|
+
* - Anthropic: 'claude-3-5-sonnet-20241022', 'claude-3-opus-20240229', 'claude-3-haiku-20240307'
|
|
30
|
+
*/
|
|
31
|
+
languageModel?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
1
34
|
/**
|
|
2
35
|
* Memory object
|
|
3
36
|
*/
|
|
@@ -60,13 +93,13 @@ export interface SearchRequest {
|
|
|
60
93
|
query: string;
|
|
61
94
|
/** Project ID to search in */
|
|
62
95
|
projectId: string;
|
|
63
|
-
/** Maximum number of results to return (default: 10) */
|
|
96
|
+
/** Maximum number of results to return (default: 10 - supermemory production default) */
|
|
64
97
|
limit?: number;
|
|
65
98
|
/** Filter criteria for search */
|
|
66
99
|
filter?: Record<string, any>;
|
|
67
|
-
/** Minimum relevance score threshold (0-1) */
|
|
100
|
+
/** Minimum relevance score threshold (0-1, default: 0.6 - supermemory production default for broad recall) */
|
|
68
101
|
threshold?: number;
|
|
69
|
-
/** Enable query rewriting (default:
|
|
102
|
+
/** Enable query rewriting (default: false - adds ~400ms latency) */
|
|
70
103
|
enableQueryRewriting?: boolean;
|
|
71
104
|
/** Enable entity expansion search (default: false) */
|
|
72
105
|
enableEntityExpansion?: boolean;
|
|
@@ -74,7 +107,7 @@ export interface SearchRequest {
|
|
|
74
107
|
enableGraphConnectivity?: boolean;
|
|
75
108
|
/** Enable semantic deduplication (default: false) */
|
|
76
109
|
enableSemanticDedup?: boolean;
|
|
77
|
-
/** Reranking strategy: 'none', 'cross-encoder', 'llm' (default: 'none') */
|
|
110
|
+
/** Reranking strategy: 'none', 'cross-encoder', 'llm' (default: 'none' - adds latency) */
|
|
78
111
|
rerankingStrategy?: 'none' | 'cross-encoder' | 'llm';
|
|
79
112
|
/** Custom fusion weights for multi-method retrieval */
|
|
80
113
|
fusionWeights?: {
|
|
@@ -84,6 +117,8 @@ export interface SearchRequest {
|
|
|
84
117
|
entity?: number;
|
|
85
118
|
graph?: number;
|
|
86
119
|
};
|
|
120
|
+
/** Model settings override (optional - uses org settings if not specified) */
|
|
121
|
+
modelSettings?: ModelSettings;
|
|
87
122
|
}
|
|
88
123
|
|
|
89
124
|
/**
|
|
@@ -132,10 +167,12 @@ export interface IngestFileRequest {
|
|
|
132
167
|
projectId: string;
|
|
133
168
|
/** Optional metadata to associate with ingested memories */
|
|
134
169
|
metadata?: Record<string, any>;
|
|
135
|
-
/** Chunk size for splitting the file (default:
|
|
170
|
+
/** Chunk size for splitting the file (default: 512 tokens - supermemory production default) */
|
|
136
171
|
chunkSize?: number;
|
|
137
|
-
/** Overlap between chunks (default:
|
|
172
|
+
/** Overlap between chunks (default: 10% - supermemory production default) */
|
|
138
173
|
chunkOverlap?: number;
|
|
174
|
+
/** Model settings override (optional - uses org settings if not specified) */
|
|
175
|
+
modelSettings?: ModelSettings;
|
|
139
176
|
}
|
|
140
177
|
|
|
141
178
|
/**
|
|
@@ -148,10 +185,12 @@ export interface IngestTextRequest {
|
|
|
148
185
|
projectId: string;
|
|
149
186
|
/** Optional metadata to associate with ingested memories */
|
|
150
187
|
metadata?: Record<string, any>;
|
|
151
|
-
/** Chunk size for splitting the text (default:
|
|
188
|
+
/** Chunk size for splitting the text (default: 512 tokens - supermemory production default) */
|
|
152
189
|
chunkSize?: number;
|
|
153
|
-
/** Overlap between chunks (default:
|
|
190
|
+
/** Overlap between chunks (default: 10% - supermemory production default) */
|
|
154
191
|
chunkOverlap?: number;
|
|
192
|
+
/** Model settings override (optional - uses org settings if not specified) */
|
|
193
|
+
modelSettings?: ModelSettings;
|
|
155
194
|
}
|
|
156
195
|
|
|
157
196
|
/**
|
|
@@ -182,11 +221,11 @@ export interface RouterRequest {
|
|
|
182
221
|
messages: Message[];
|
|
183
222
|
/** Project ID for memory context */
|
|
184
223
|
projectId: string;
|
|
185
|
-
/** Model to use (
|
|
224
|
+
/** Model to use (default: 'gpt-4o-mini' - supermemory production default) */
|
|
186
225
|
model?: string;
|
|
187
|
-
/** Temperature for generation (0-2, default:
|
|
226
|
+
/** Temperature for generation (0-2, default: 0.7 - supermemory production default) */
|
|
188
227
|
temperature?: number;
|
|
189
|
-
/** Maximum tokens to generate */
|
|
228
|
+
/** Maximum tokens to generate (default: 2000 - supermemory production default) */
|
|
190
229
|
maxTokens?: number;
|
|
191
230
|
/** Whether to stream the response */
|
|
192
231
|
stream?: boolean;
|