@memorylayerai/sdk 0.1.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.
@@ -0,0 +1,144 @@
1
+ import { HTTPClient } from '../http-client.js';
2
+ import {
3
+ Memory,
4
+ CreateMemoryRequest,
5
+ UpdateMemoryRequest,
6
+ ListMemoriesRequest,
7
+ } from '../types.js';
8
+ import { ValidationError } from '../errors.js';
9
+
10
+ /**
11
+ * Resource for memory operations
12
+ */
13
+ export class MemoriesResource {
14
+ constructor(private httpClient: HTTPClient) {}
15
+
16
+ /**
17
+ * Add a new memory
18
+ * @param request - Memory creation request
19
+ * @returns The created memory
20
+ */
21
+ async add(request: CreateMemoryRequest): Promise<Memory> {
22
+ // Validate request
23
+ if (!request.content || request.content.trim().length === 0) {
24
+ throw new ValidationError(
25
+ 'Memory content cannot be empty',
26
+ [{ field: 'content', message: 'Content is required and cannot be empty' }]
27
+ );
28
+ }
29
+
30
+ if (!request.projectId || request.projectId.trim().length === 0) {
31
+ throw new ValidationError(
32
+ 'Project ID is required',
33
+ [{ field: 'projectId', message: 'Project ID is required' }]
34
+ );
35
+ }
36
+
37
+ return this.httpClient.request<Memory>({
38
+ method: 'POST',
39
+ path: '/v1/memories',
40
+ body: request,
41
+ });
42
+ }
43
+
44
+ /**
45
+ * Get a memory by ID
46
+ * @param id - Memory ID
47
+ * @returns The memory
48
+ */
49
+ async get(id: string): Promise<Memory> {
50
+ if (!id || id.trim().length === 0) {
51
+ throw new ValidationError(
52
+ 'Memory ID is required',
53
+ [{ field: 'id', message: 'Memory ID is required' }]
54
+ );
55
+ }
56
+
57
+ return this.httpClient.request<Memory>({
58
+ method: 'GET',
59
+ path: `/v1/memories/${id}`,
60
+ });
61
+ }
62
+
63
+ /**
64
+ * Update a memory
65
+ * @param id - Memory ID
66
+ * @param request - Update request
67
+ * @returns The updated memory
68
+ */
69
+ async update(id: string, request: UpdateMemoryRequest): Promise<Memory> {
70
+ if (!id || id.trim().length === 0) {
71
+ throw new ValidationError(
72
+ 'Memory ID is required',
73
+ [{ field: 'id', message: 'Memory ID is required' }]
74
+ );
75
+ }
76
+
77
+ if (!request.content && !request.metadata) {
78
+ throw new ValidationError(
79
+ 'At least one of content or metadata must be provided',
80
+ [{ field: 'request', message: 'Nothing to update' }]
81
+ );
82
+ }
83
+
84
+ return this.httpClient.request<Memory>({
85
+ method: 'PATCH',
86
+ path: `/v1/memories/${id}`,
87
+ body: request,
88
+ });
89
+ }
90
+
91
+ /**
92
+ * Delete a memory
93
+ * @param id - Memory ID
94
+ */
95
+ async delete(id: string): Promise<void> {
96
+ if (!id || id.trim().length === 0) {
97
+ throw new ValidationError(
98
+ 'Memory ID is required',
99
+ [{ field: 'id', message: 'Memory ID is required' }]
100
+ );
101
+ }
102
+
103
+ await this.httpClient.request<void>({
104
+ method: 'DELETE',
105
+ path: `/v1/memories/${id}`,
106
+ });
107
+ }
108
+
109
+ /**
110
+ * List memories
111
+ * @param request - List request with filters
112
+ * @returns Array of memories
113
+ */
114
+ async list(request: ListMemoriesRequest): Promise<Memory[]> {
115
+ if (!request.projectId || request.projectId.trim().length === 0) {
116
+ throw new ValidationError(
117
+ 'Project ID is required',
118
+ [{ field: 'projectId', message: 'Project ID is required' }]
119
+ );
120
+ }
121
+
122
+ const query: Record<string, string> = {
123
+ projectId: request.projectId,
124
+ };
125
+
126
+ if (request.limit !== undefined) {
127
+ query.limit = request.limit.toString();
128
+ }
129
+
130
+ if (request.offset !== undefined) {
131
+ query.offset = request.offset.toString();
132
+ }
133
+
134
+ if (request.filter) {
135
+ query.filter = JSON.stringify(request.filter);
136
+ }
137
+
138
+ return this.httpClient.request<Memory[]>({
139
+ method: 'GET',
140
+ path: '/v1/memories',
141
+ query,
142
+ });
143
+ }
144
+ }
@@ -0,0 +1,81 @@
1
+ import { HTTPClient } from '../http-client.js';
2
+ import { RouterRequest, RouterResponse, StreamChunk } from '../types.js';
3
+ import { ValidationError } from '../errors.js';
4
+
5
+ /**
6
+ * Resource for router operations
7
+ */
8
+ export class RouterResource {
9
+ constructor(private httpClient: HTTPClient) {}
10
+
11
+ /**
12
+ * Complete a router request (non-streaming)
13
+ * @param request - Router request
14
+ * @returns Router response
15
+ */
16
+ async complete(request: RouterRequest): Promise<RouterResponse> {
17
+ // Validate request
18
+ if (!request.messages || request.messages.length === 0) {
19
+ throw new ValidationError(
20
+ 'Messages array cannot be empty',
21
+ [{ field: 'messages', message: 'At least one message is required' }]
22
+ );
23
+ }
24
+
25
+ if (!request.projectId || request.projectId.trim().length === 0) {
26
+ throw new ValidationError(
27
+ 'Project ID is required',
28
+ [{ field: 'projectId', message: 'Project ID is required' }]
29
+ );
30
+ }
31
+
32
+ return this.httpClient.request<RouterResponse>({
33
+ method: 'POST',
34
+ path: '/v1/router/complete',
35
+ body: {
36
+ ...request,
37
+ stream: false,
38
+ },
39
+ });
40
+ }
41
+
42
+ /**
43
+ * Stream a router request
44
+ * @param request - Router request
45
+ * @returns Async iterable of stream chunks
46
+ */
47
+ async *stream(request: RouterRequest): AsyncIterable<StreamChunk> {
48
+ // Validate request
49
+ if (!request.messages || request.messages.length === 0) {
50
+ throw new ValidationError(
51
+ 'Messages array cannot be empty',
52
+ [{ field: 'messages', message: 'At least one message is required' }]
53
+ );
54
+ }
55
+
56
+ if (!request.projectId || request.projectId.trim().length === 0) {
57
+ throw new ValidationError(
58
+ 'Project ID is required',
59
+ [{ field: 'projectId', message: 'Project ID is required' }]
60
+ );
61
+ }
62
+
63
+ const stream = this.httpClient.stream({
64
+ method: 'POST',
65
+ path: '/v1/router/complete',
66
+ body: {
67
+ ...request,
68
+ stream: true,
69
+ },
70
+ });
71
+
72
+ try {
73
+ for await (const chunk of stream) {
74
+ yield chunk as StreamChunk;
75
+ }
76
+ } catch (error) {
77
+ // Stream errors are already handled by HTTPClient
78
+ throw error;
79
+ }
80
+ }
81
+ }
@@ -0,0 +1,55 @@
1
+ import { HTTPClient } from '../http-client.js';
2
+ import { SearchRequest, SearchResponse } from '../types.js';
3
+ import { ValidationError } from '../errors.js';
4
+
5
+ /**
6
+ * Resource for search operations
7
+ */
8
+ export class SearchResource {
9
+ constructor(private httpClient: HTTPClient) {}
10
+
11
+ /**
12
+ * Search memories
13
+ * @param request - Search request
14
+ * @returns Search results
15
+ */
16
+ async search(request: SearchRequest): Promise<SearchResponse> {
17
+ // Validate request
18
+ if (!request.query || request.query.trim().length === 0) {
19
+ throw new ValidationError(
20
+ 'Search query cannot be empty',
21
+ [{ field: 'query', message: 'Query is required and cannot be empty' }]
22
+ );
23
+ }
24
+
25
+ if (!request.projectId || request.projectId.trim().length === 0) {
26
+ throw new ValidationError(
27
+ 'Project ID is required',
28
+ [{ field: 'projectId', message: 'Project ID is required' }]
29
+ );
30
+ }
31
+
32
+ const query: Record<string, string> = {
33
+ q: request.query,
34
+ projectId: request.projectId,
35
+ };
36
+
37
+ if (request.limit !== undefined) {
38
+ query.limit = request.limit.toString();
39
+ }
40
+
41
+ if (request.threshold !== undefined) {
42
+ query.threshold = request.threshold.toString();
43
+ }
44
+
45
+ if (request.filter) {
46
+ query.filter = JSON.stringify(request.filter);
47
+ }
48
+
49
+ return this.httpClient.request<SearchResponse>({
50
+ method: 'GET',
51
+ path: '/v1/search',
52
+ query,
53
+ });
54
+ }
55
+ }
package/src/types.ts ADDED
@@ -0,0 +1,225 @@
1
+ /**
2
+ * Memory object
3
+ */
4
+ export interface Memory {
5
+ /** Unique identifier for the memory */
6
+ id: string;
7
+ /** Content of the memory */
8
+ content: string;
9
+ /** Optional metadata associated with the memory */
10
+ metadata?: Record<string, any>;
11
+ /** Project ID this memory belongs to */
12
+ projectId: string;
13
+ /** Timestamp when the memory was created */
14
+ createdAt: string;
15
+ /** Timestamp when the memory was last updated */
16
+ updatedAt: string;
17
+ }
18
+
19
+ /**
20
+ * Request to create a new memory
21
+ */
22
+ export interface CreateMemoryRequest {
23
+ /** Content of the memory */
24
+ content: string;
25
+ /** Optional metadata to associate with the memory */
26
+ metadata?: Record<string, any>;
27
+ /** Project ID to create the memory in */
28
+ projectId: string;
29
+ }
30
+
31
+ /**
32
+ * Request to update an existing memory
33
+ */
34
+ export interface UpdateMemoryRequest {
35
+ /** New content for the memory (optional) */
36
+ content?: string;
37
+ /** New metadata for the memory (optional) */
38
+ metadata?: Record<string, any>;
39
+ }
40
+
41
+ /**
42
+ * Request to list memories
43
+ */
44
+ export interface ListMemoriesRequest {
45
+ /** Project ID to list memories from */
46
+ projectId: string;
47
+ /** Maximum number of memories to return (default: 100) */
48
+ limit?: number;
49
+ /** Number of memories to skip (default: 0) */
50
+ offset?: number;
51
+ /** Filter criteria for memories */
52
+ filter?: Record<string, any>;
53
+ }
54
+
55
+ /**
56
+ * Search request
57
+ */
58
+ export interface SearchRequest {
59
+ /** Search query */
60
+ query: string;
61
+ /** Project ID to search in */
62
+ projectId: string;
63
+ /** Maximum number of results to return (default: 10) */
64
+ limit?: number;
65
+ /** Filter criteria for search */
66
+ filter?: Record<string, any>;
67
+ /** Minimum relevance score threshold (0-1) */
68
+ threshold?: number;
69
+ }
70
+
71
+ /**
72
+ * Search result
73
+ */
74
+ export interface SearchResult {
75
+ /** The memory that matched the search */
76
+ memory: Memory;
77
+ /** Relevance score (0-1) */
78
+ score: number;
79
+ /** Highlighted text snippets */
80
+ highlights?: string[];
81
+ }
82
+
83
+ /**
84
+ * Search response
85
+ */
86
+ export interface SearchResponse {
87
+ /** Array of search results */
88
+ results: SearchResult[];
89
+ /** Total number of results found */
90
+ total: number;
91
+ }
92
+
93
+ /**
94
+ * Request to ingest a file
95
+ */
96
+ export interface IngestFileRequest {
97
+ /** File to ingest (Buffer, Blob, or File) */
98
+ file: Buffer | Blob | File;
99
+ /** Project ID to ingest into */
100
+ projectId: string;
101
+ /** Optional metadata to associate with ingested memories */
102
+ metadata?: Record<string, any>;
103
+ /** Chunk size for splitting the file (default: 1000) */
104
+ chunkSize?: number;
105
+ /** Overlap between chunks (default: 200) */
106
+ chunkOverlap?: number;
107
+ }
108
+
109
+ /**
110
+ * Request to ingest text
111
+ */
112
+ export interface IngestTextRequest {
113
+ /** Text to ingest */
114
+ text: string;
115
+ /** Project ID to ingest into */
116
+ projectId: string;
117
+ /** Optional metadata to associate with ingested memories */
118
+ metadata?: Record<string, any>;
119
+ /** Chunk size for splitting the text (default: 1000) */
120
+ chunkSize?: number;
121
+ /** Overlap between chunks (default: 200) */
122
+ chunkOverlap?: number;
123
+ }
124
+
125
+ /**
126
+ * Ingestion response
127
+ */
128
+ export interface IngestResponse {
129
+ /** IDs of the created memories */
130
+ memoryIds: string[];
131
+ /** Number of chunks created */
132
+ chunksCreated: number;
133
+ }
134
+
135
+ /**
136
+ * Message in a conversation
137
+ */
138
+ export interface Message {
139
+ /** Role of the message sender */
140
+ role: 'user' | 'assistant' | 'system';
141
+ /** Content of the message */
142
+ content: string;
143
+ }
144
+
145
+ /**
146
+ * Router request
147
+ */
148
+ export interface RouterRequest {
149
+ /** Array of messages in the conversation */
150
+ messages: Message[];
151
+ /** Project ID for memory context */
152
+ projectId: string;
153
+ /** Model to use (optional) */
154
+ model?: string;
155
+ /** Temperature for generation (0-2, default: 1) */
156
+ temperature?: number;
157
+ /** Maximum tokens to generate */
158
+ maxTokens?: number;
159
+ /** Whether to stream the response */
160
+ stream?: boolean;
161
+ }
162
+
163
+ /**
164
+ * Token usage information
165
+ */
166
+ export interface Usage {
167
+ /** Number of tokens in the prompt */
168
+ promptTokens: number;
169
+ /** Number of tokens in the completion */
170
+ completionTokens: number;
171
+ /** Total number of tokens used */
172
+ totalTokens: number;
173
+ }
174
+
175
+ /**
176
+ * Choice in a router response
177
+ */
178
+ export interface Choice {
179
+ /** The generated message */
180
+ message: Message;
181
+ /** Reason why generation finished */
182
+ finishReason: string;
183
+ }
184
+
185
+ /**
186
+ * Router response
187
+ */
188
+ export interface RouterResponse {
189
+ /** Unique identifier for the response */
190
+ id: string;
191
+ /** Array of choices (usually one) */
192
+ choices: Choice[];
193
+ /** Token usage information */
194
+ usage: Usage;
195
+ }
196
+
197
+ /**
198
+ * Delta in a streaming choice
199
+ */
200
+ export interface StreamDelta {
201
+ /** Role of the message (only in first chunk) */
202
+ role?: string;
203
+ /** Content chunk */
204
+ content?: string;
205
+ }
206
+
207
+ /**
208
+ * Choice in a streaming response
209
+ */
210
+ export interface StreamChoice {
211
+ /** Delta containing the new content */
212
+ delta: StreamDelta;
213
+ /** Reason why generation finished (only in last chunk) */
214
+ finishReason?: string;
215
+ }
216
+
217
+ /**
218
+ * Streaming chunk from router
219
+ */
220
+ export interface StreamChunk {
221
+ /** Unique identifier for the response */
222
+ id: string;
223
+ /** Array of streaming choices */
224
+ choices: StreamChoice[];
225
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ESNext",
5
+ "lib": ["ES2020"],
6
+ "moduleResolution": "node",
7
+ "declaration": true,
8
+ "declarationMap": true,
9
+ "sourceMap": true,
10
+ "outDir": "./dist",
11
+ "rootDir": "./src",
12
+ "strict": true,
13
+ "esModuleInterop": true,
14
+ "skipLibCheck": true,
15
+ "forceConsistentCasingInFileNames": true,
16
+ "resolveJsonModule": true,
17
+ "isolatedModules": true,
18
+ "noUnusedLocals": true,
19
+ "noUnusedParameters": true,
20
+ "noImplicitReturns": true,
21
+ "noFallthroughCasesInSwitch": true
22
+ },
23
+ "include": ["src/**/*"],
24
+ "exclude": ["node_modules", "dist", "**/*.test.ts"]
25
+ }
@@ -0,0 +1,13 @@
1
+ import { defineConfig } from 'vitest/config';
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ globals: true,
6
+ environment: 'node',
7
+ coverage: {
8
+ provider: 'v8',
9
+ reporter: ['text', 'json', 'html'],
10
+ exclude: ['**/*.test.ts', '**/dist/**', '**/node_modules/**']
11
+ }
12
+ }
13
+ });