@danielzfliu/memory 2.0.0 → 2.2.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,455 @@
1
+ # REST API
2
+
3
+ Use Memory as a standalone HTTP service.
4
+
5
+ ## Start the server
6
+
7
+ After completing [Getting Started](./getting-started.md):
8
+
9
+ ### Development
10
+
11
+ ```bash
12
+ npm run dev:http
13
+ ```
14
+
15
+ ### Production-style run
16
+
17
+ ```bash
18
+ npm run build
19
+ npm run start:http
20
+ ```
21
+
22
+ The server listens on `http://localhost:3000` by default. Set `PORT` to change it.
23
+
24
+ See [Configuration](./configuration.md) for runtime options such as CORS and request logging.
25
+
26
+ ## API contract
27
+
28
+ Base URL: `http://localhost:3000`
29
+
30
+ All request bodies are JSON. Success responses are also JSON unless the status is `204 No Content`.
31
+
32
+ ### Shared response shapes
33
+
34
+ `Piece`
35
+
36
+ | Field | Type | Description |
37
+ |------|------|-------------|
38
+ | `id` | `string` | Server-generated UUID |
39
+ | `content` | `string` | Stored text content |
40
+ | `title` | `string` | Optional human-readable title |
41
+ | `tags` | `string[]` | Tags associated with the piece |
42
+
43
+ Example:
44
+
45
+ ```json
46
+ {
47
+ "id": "2f7b8d6a-0f34-4a1f-85c0-5a7f4cce7c4d",
48
+ "title": "TypeScript overview",
49
+ "content": "TypeScript is a typed superset of JavaScript.",
50
+ "tags": ["typescript", "programming"]
51
+ }
52
+ ```
53
+
54
+ `QueryResult`
55
+
56
+ ```json
57
+ {
58
+ "piece": {
59
+ "id": "2f7b8d6a-0f34-4a1f-85c0-5a7f4cce7c4d",
60
+ "title": "TypeScript overview",
61
+ "content": "TypeScript is a typed superset of JavaScript.",
62
+ "tags": ["typescript", "programming"]
63
+ },
64
+ "score": 0.87
65
+ }
66
+ ```
67
+
68
+ `RagResult`
69
+
70
+ ```json
71
+ {
72
+ "answer": "TypeScript adds a type system on top of JavaScript. [1]",
73
+ "sources": [
74
+ {
75
+ "piece": {
76
+ "id": "2f7b8d6a-0f34-4a1f-85c0-5a7f4cce7c4d",
77
+ "title": "TypeScript overview",
78
+ "content": "TypeScript is a typed superset of JavaScript.",
79
+ "tags": ["typescript", "programming"]
80
+ },
81
+ "score": 0.87
82
+ }
83
+ ]
84
+ }
85
+ ```
86
+
87
+ `ErrorResponse`
88
+
89
+ ```json
90
+ {
91
+ "error": "content (string) is required"
92
+ }
93
+ ```
94
+
95
+ `ServiceUnavailableResponse`
96
+
97
+ ```json
98
+ {
99
+ "error": "Failed to connect to ChromaDB",
100
+ "details": "Error: ..."
101
+ }
102
+ ```
103
+
104
+ `HealthResponse`
105
+
106
+ ```json
107
+ {
108
+ "status": "ok",
109
+ "services": {
110
+ "api": {
111
+ "status": "ok"
112
+ },
113
+ "chromadb": {
114
+ "status": "ok"
115
+ },
116
+ "ollama": {
117
+ "status": "ok",
118
+ "modelCount": 7
119
+ }
120
+ }
121
+ }
122
+ ```
123
+
124
+ > **Multi-collection:** All piece and query endpoints accept an optional `collection` parameter to target a specific collection. For `POST` and `PUT`, pass it in the JSON body. For `GET` and `DELETE`, pass it as a query parameter. Omitting it uses the default collection.
125
+
126
+ ### `GET /health`
127
+
128
+ Report the health of the API, ChromaDB, and Ollama.
129
+
130
+ Responses:
131
+
132
+ | Status | Body |
133
+ |--------|------|
134
+ | `200` | `HealthResponse` with `status: "ok"` |
135
+ | `503` | `HealthResponse` with `status: "degraded"` |
136
+
137
+ Notes:
138
+
139
+ | Field | Description |
140
+ |------|-------------|
141
+ | `services.api.status` | Always `ok` when the API process is responding |
142
+ | `services.chromadb.status` | `ok` when ChromaDB is reachable |
143
+ | `services.ollama.status` | `ok` when Ollama responds successfully to `/api/tags` |
144
+ | `services.ollama.modelCount` | Present when the Ollama health check returns a model list |
145
+
146
+ Example:
147
+
148
+ ```bash
149
+ curl http://localhost:3000/health
150
+ ```
151
+
152
+ ### `GET /pieces`
153
+
154
+ List pieces from a collection, optionally paginated.
155
+
156
+ Query parameters:
157
+
158
+ | Name | Type | Required | Description |
159
+ |------|------|----------|-------------|
160
+ | `collection` | `string` | No | Optional target collection |
161
+ | `limit` | `number` | No | Positive integer maximum number of pieces to return |
162
+ | `offset` | `number` | No | Non-negative integer number of pieces to skip |
163
+
164
+ Responses:
165
+
166
+ | Status | Body |
167
+ |--------|------|
168
+ | `200` | `{ "pieces": Piece[] }` |
169
+ | `400` | `ErrorResponse` |
170
+ | `500` | `ErrorResponse` |
171
+ | `503` | `ServiceUnavailableResponse` |
172
+
173
+ Example:
174
+
175
+ ```bash
176
+ curl http://localhost:3000/pieces
177
+ curl "http://localhost:3000/pieces?collection=agent-alice&limit=20&offset=40"
178
+ ```
179
+
180
+ ### `GET /tags`
181
+
182
+ List unique tags from a collection in sorted order.
183
+
184
+ Query parameters:
185
+
186
+ | Name | Type | Required | Description |
187
+ |------|------|----------|-------------|
188
+ | `collection` | `string` | No | Optional target collection |
189
+ | `limit` | `number` | No | Positive integer maximum number of tags to return |
190
+ | `offset` | `number` | No | Non-negative integer number of tags to skip |
191
+
192
+ Responses:
193
+
194
+ | Status | Body |
195
+ |--------|------|
196
+ | `200` | `{ "tags": string[] }` |
197
+ | `400` | `ErrorResponse` |
198
+ | `500` | `ErrorResponse` |
199
+ | `503` | `ServiceUnavailableResponse` |
200
+
201
+ Example:
202
+
203
+ ```bash
204
+ curl http://localhost:3000/tags
205
+ curl "http://localhost:3000/tags?collection=agent-alice&limit=25&offset=0"
206
+ ```
207
+
208
+ ### `POST /pieces`
209
+
210
+ Create a new piece.
211
+
212
+ Request body:
213
+
214
+ | Field | Type | Required | Description |
215
+ |------|------|----------|-------------|
216
+ | `content` | `string` | Yes | Piece text to store |
217
+ | `title` | `string` | No | Optional title |
218
+ | `tags` | `string[]` | No | Optional tags; defaults to `[]` |
219
+ | `collection` | `string` | No | Optional target collection |
220
+
221
+ Responses:
222
+
223
+ | Status | Body |
224
+ |--------|------|
225
+ | `201` | `Piece` |
226
+ | `400` | `ErrorResponse` |
227
+ | `500` | `ErrorResponse` |
228
+ | `503` | `ServiceUnavailableResponse` |
229
+
230
+ Example:
231
+
232
+ ```bash
233
+ curl -X POST http://localhost:3000/pieces \
234
+ -H "Content-Type: application/json" \
235
+ -d '{"title": "TypeScript overview", "content": "TypeScript is a typed superset of JavaScript.", "tags": ["typescript", "programming"]}'
236
+ ```
237
+
238
+ ### `GET /pieces/:id`
239
+
240
+ Fetch a piece by ID.
241
+
242
+ Query parameters:
243
+
244
+ | Name | Type | Required | Description |
245
+ |------|------|----------|-------------|
246
+ | `collection` | `string` | No | Optional target collection |
247
+
248
+ Responses:
249
+
250
+ | Status | Body |
251
+ |--------|------|
252
+ | `200` | `Piece` |
253
+ | `404` | `ErrorResponse` with `"Piece not found"` |
254
+ | `500` | `ErrorResponse` |
255
+ | `503` | `ServiceUnavailableResponse` |
256
+
257
+ Example:
258
+
259
+ ```bash
260
+ curl http://localhost:3000/pieces/<id>
261
+ curl http://localhost:3000/pieces/<id>?collection=agent-alice
262
+ ```
263
+
264
+ ### `PUT /pieces/:id`
265
+
266
+ Update an existing piece. Any omitted field keeps its current value.
267
+
268
+ Request body:
269
+
270
+ | Field | Type | Required | Description |
271
+ |------|------|----------|-------------|
272
+ | `content` | `string` | No | Updated piece content |
273
+ | `title` | `string \| null` | No | Updated title; pass `null` to clear it |
274
+ | `tags` | `string[]` | No | Replacement tag list |
275
+ | `collection` | `string` | No | Optional target collection |
276
+
277
+ Responses:
278
+
279
+ | Status | Body |
280
+ |--------|------|
281
+ | `200` | `Piece` |
282
+ | `400` | `ErrorResponse` |
283
+ | `404` | `ErrorResponse` with `"Piece not found"` |
284
+ | `500` | `ErrorResponse` |
285
+ | `503` | `ServiceUnavailableResponse` |
286
+
287
+ Example:
288
+
289
+ ```bash
290
+ curl -X PUT http://localhost:3000/pieces/<id> \
291
+ -H "Content-Type: application/json" \
292
+ -d '{"title": "Updated title", "content": "Updated content.", "tags": ["new-tag"]}'
293
+ ```
294
+
295
+ ### `DELETE /pieces/:id`
296
+
297
+ Delete a piece by ID.
298
+
299
+ Query parameters:
300
+
301
+ | Name | Type | Required | Description |
302
+ |------|------|----------|-------------|
303
+ | `collection` | `string` | No | Optional target collection |
304
+
305
+ Responses:
306
+
307
+ | Status | Body |
308
+ |--------|------|
309
+ | `204` | No body |
310
+ | `500` | `ErrorResponse` |
311
+ | `503` | `ServiceUnavailableResponse` |
312
+
313
+ Example:
314
+
315
+ ```bash
316
+ curl -X DELETE http://localhost:3000/pieces/<id>
317
+ curl -X DELETE http://localhost:3000/pieces/<id>?collection=agent-alice
318
+ ```
319
+
320
+ ### `POST /query`
321
+
322
+ Run semantic search over stored pieces.
323
+
324
+ Request body:
325
+
326
+ | Field | Type | Required | Description |
327
+ |------|------|----------|-------------|
328
+ | `query` | `string` | Yes | Search query |
329
+ | `tags` | `string[]` | No | Restrict matches to pieces containing these tags |
330
+ | `topK` | `number` | No | Positive integer result count; defaults to `10` |
331
+ | `useHybridSearch` | `boolean` | No | When `true`, combine vector and keyword ranking |
332
+ | `collection` | `string` | No | Optional target collection |
333
+
334
+ Responses:
335
+
336
+ | Status | Body |
337
+ |--------|------|
338
+ | `200` | `QueryResult[]` |
339
+ | `400` | `ErrorResponse` |
340
+ | `500` | `ErrorResponse` |
341
+ | `503` | `ServiceUnavailableResponse` |
342
+
343
+ Example:
344
+
345
+ ```bash
346
+ curl -X POST http://localhost:3000/query \
347
+ -H "Content-Type: application/json" \
348
+ -d '{"query": "What is TypeScript?", "topK": 5}'
349
+ ```
350
+
351
+ With tag filtering:
352
+
353
+ ```bash
354
+ curl -X POST http://localhost:3000/query \
355
+ -H "Content-Type: application/json" \
356
+ -d '{"query": "What is TypeScript?", "tags": ["programming"], "topK": 5}'
357
+ ```
358
+
359
+ With hybrid search:
360
+
361
+ ```bash
362
+ curl -X POST http://localhost:3000/query \
363
+ -H "Content-Type: application/json" \
364
+ -d '{"query": "What is TypeScript?", "topK": 5, "useHybridSearch": true}'
365
+ ```
366
+
367
+ ### `POST /rag`
368
+
369
+ Run retrieval and then ask the configured generation model to answer using only the retrieved context.
370
+
371
+ Request body:
372
+
373
+ | Field | Type | Required | Description |
374
+ |------|------|----------|-------------|
375
+ | `query` | `string` | Yes | User question |
376
+ | `tags` | `string[]` | No | Restrict retrieval to matching tags |
377
+ | `topK` | `number` | No | Positive integer source count; defaults to `10` |
378
+ | `useHybridSearch` | `boolean` | No | When `true`, combine vector and keyword ranking before generation |
379
+ | `collection` | `string` | No | Optional target collection |
380
+
381
+ Responses:
382
+
383
+ | Status | Body |
384
+ |--------|------|
385
+ | `200` | `RagResult` |
386
+ | `400` | `ErrorResponse` |
387
+ | `500` | `ErrorResponse` |
388
+ | `503` | `ServiceUnavailableResponse` |
389
+
390
+ Example:
391
+
392
+ ```bash
393
+ curl -X POST http://localhost:3000/rag \
394
+ -H "Content-Type: application/json" \
395
+ -d '{"query": "Explain TypeScript", "tags": ["programming"], "topK": 5}'
396
+ ```
397
+
398
+ If no relevant pieces are found, the server still returns `200` with an answer explaining that there is not enough context and `sources: []`.
399
+
400
+ ### `GET /collections`
401
+
402
+ List available collections.
403
+
404
+ Responses:
405
+
406
+ | Status | Body |
407
+ |--------|------|
408
+ | `200` | `{ "collections": string[] }` |
409
+ | `500` | `ErrorResponse` |
410
+ | `503` | `ServiceUnavailableResponse` |
411
+
412
+ Example:
413
+
414
+ ```bash
415
+ curl http://localhost:3000/collections
416
+ ```
417
+
418
+ ### `PUT /collections/:name`
419
+
420
+ Ensure a collection exists.
421
+
422
+ This endpoint is idempotent and returns success whether the collection is newly created or already present.
423
+
424
+ Responses:
425
+
426
+ | Status | Body |
427
+ |--------|------|
428
+ | `204` | No body |
429
+ | `400` | `ErrorResponse` |
430
+ | `500` | `ErrorResponse` |
431
+ | `503` | `ServiceUnavailableResponse` |
432
+
433
+ Example:
434
+
435
+ ```bash
436
+ curl -X PUT http://localhost:3000/collections/agent-alice
437
+ ```
438
+
439
+ ### `DELETE /collections/:name`
440
+
441
+ Delete a collection by name.
442
+
443
+ Responses:
444
+
445
+ | Status | Body |
446
+ |--------|------|
447
+ | `204` | No body |
448
+ | `500` | `ErrorResponse` |
449
+ | `503` | `ServiceUnavailableResponse` |
450
+
451
+ Example:
452
+
453
+ ```bash
454
+ curl -X DELETE http://localhost:3000/collections/agent-alice
455
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danielzfliu/memory",
3
- "version": "2.0.0",
3
+ "version": "2.2.0",
4
4
  "description": "A local MCP server and Node.js library for storing, searching, and querying tagged text pieces using ChromaDB and Ollama",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -15,6 +15,7 @@
15
15
  },
16
16
  "files": [
17
17
  "dist",
18
+ "docs",
18
19
  "README.md",
19
20
  "LICENSE"
20
21
  ],
@@ -66,6 +67,7 @@
66
67
  "@types/express": "^5.0.0",
67
68
  "@types/supertest": "^6.0.3",
68
69
  "@types/uuid": "^10.0.0",
70
+ "@vitest/coverage-v8": "^4.0.18",
69
71
  "supertest": "^7.2.2",
70
72
  "tsx": "^4.19.0",
71
73
  "typescript": "^5.6.0",