@pyxmate/memory 0.6.3 → 0.9.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pyxmate/memory",
3
- "version": "0.6.3",
3
+ "version": "0.9.0",
4
4
  "type": "module",
5
5
  "description": "SDK for pyx-memory — Memory as a Service for AI agents",
6
6
  "license": "MIT",
@@ -91,7 +91,9 @@ curl -s -X POST {{ENDPOINT}}/api/memory/ingest/file \
91
91
  -F "description=What this file contains or shows"
92
92
  ```
93
93
 
94
- Supported formats: txt, md, csv, pdf, docx, json, jsonl, html, png, jpg, jpeg, webp, gif, bmp, tiff, svg (50MB limit).
94
+ Supported formats: txt, md, csv, tsv, log, pdf, docx, xlsx, pptx, json, jsonl, html, htm, png, jpg, jpeg, webp, gif, bmp, tiff, svg (100MB limit).
95
+
96
+ Ingestion streams from disk — parsers read row-by-row (csv/xlsx), line-by-line (txt/jsonl), page-by-page (pdf), or slide-by-slide (pptx) so peak memory is bounded regardless of file size. The only exception is `.docx`, which is hard-capped at 10MB because the underlying library (mammoth) loads the whole document into memory; above 10MB the server returns an error asking you to pre-extract the text upstream and re-upload as `.txt` or `.md`.
95
97
 
96
98
  **Images require a `description`** — this is how the content gets embedded and becomes searchable. Without it, the image is stored but not findable. Use your vision capabilities to generate the description when the user doesn't provide one.
97
99
 
@@ -25,7 +25,7 @@ const client = new MemoryClient('http://localhost:7822', process.env.MEMORY_API_
25
25
  | GET | `/health` | Public health check (status only — no internals exposed) |
26
26
  | GET | `/admin/health` | Admin health check (version, uptime, embedding provider, memory stats) |
27
27
  | POST | `/api/memory/ingest` | Store a memory (JSON: `{ content, type, metadata, agentId?, sessionId?, targets?, entities?, relationships?, importance?, source?, eventTime?, id?, parentId?, ingestTime? }`) |
28
- | POST | `/api/memory/ingest/file` | Upload file (multipart, 50MB limit). For PDFs with images, returns an `enrichment` block with HMAC token and image metadata for two-phase enrichment. |
28
+ | POST | `/api/memory/ingest/file` | Upload file (multipart, 100MB limit). For PDFs with images, returns an `enrichment` block with HMAC token and image metadata for two-phase enrichment. |
29
29
  | GET | `/api/memory/files/download/:filename` | Download uploaded file binary by filename. Returns the original file with proper Content-Type. Images served inline, documents as attachment. |
30
30
  | GET | `/api/memory/files/:fileId/images/:imageId?token=...` | Fetch an extracted PDF image (binary). Requires HMAC token from ingest response. |
31
31
  | POST | `/api/memory/files/:fileId/enrich` | Submit image descriptions + entities after LLM vision processing. Requires `X-Enrichment-Token` header. |
@@ -66,22 +66,57 @@ const client = new MemoryClient('http://localhost:7822', process.env.MEMORY_API_
66
66
 
67
67
  | Field | Type | Required | Description |
68
68
  |-------|------|----------|-------------|
69
- | `file` | File | Yes | The file to ingest (max 50MB) |
69
+ | `file` | File | Yes | The file to ingest (max 100MB) |
70
70
  | `description` | string | No | Agent-provided description (e.g., from LLM vision). Used instead of parser output for images. |
71
71
 
72
- **Supported formats**: `.txt`, `.md`, `.csv`, `.pdf`, `.docx`, `.json`, `.jsonl`, `.html`, `.htm`, `.log`, `.tsv`, `.png`, `.jpg`, `.jpeg`, `.webp`, `.gif`, `.bmp`, `.tiff`, `.svg`
72
+ **Supported formats**: `.txt`, `.md`, `.csv`, `.tsv`, `.log`, `.pdf`, `.docx`, `.xlsx`, `.pptx`, `.json`, `.jsonl`, `.html`, `.htm`, `.png`, `.jpg`, `.jpeg`, `.webp`, `.gif`, `.bmp`, `.tiff`, `.svg`
73
+
74
+ **Memory behavior**: All text parsers (csv, tsv, txt, log, pdf, json, jsonl, html, xlsx, pptx) stream from disk during ingestion — peak server memory is bounded to a few MB regardless of file size, up to the 100MB file limit. `.docx` is the exception: mammoth (the parser) has no streaming API, so `.docx` is hard-capped at 10MB on the server. Above 10MB the server returns a `MemoryError` asking you to pre-extract the text upstream and re-upload as `.txt` or `.md`.
73
75
 
74
76
  **What happens on upload**:
75
77
  1. Original file is saved to `{DATA_DIR}/files/{filename}` (persistent across restarts)
76
78
  2. Text is extracted (documents) or description is used (images)
77
79
  3. Content is chunked and stored in SQLite + vector for semantic search
78
80
  4. Source-aware dedup: re-uploading the same filename replaces the previous version
79
- 5. **PDFs with images**: Images are extracted via pdfjs-dist, saved to a temp directory, and an `enrichment` block is returned with HMAC-signed tokens for two-phase enrichment
81
+ 5. **PDFs with images**: Images are extracted via poppler (`pdfimages` for embedded objects, `pdftoppm` for page renders on scanned PDFs), saved to a temp directory, and an `enrichment` block is returned with HMAC-signed tokens for two-phase enrichment. `pdf-parse` is used only as a dev fallback for small files (<5MB) when poppler isn't installed.
80
82
 
81
83
  **Image ingestion**: Images cannot have text extracted. Pass a `description` field with a natural-language description (e.g., from an LLM with vision). Without a description, images get a minimal placeholder (`[Image] filename (size KB)`).
82
84
 
83
85
  **PDF enrichment**: When a PDF contains images (≥50x50px), the response includes an `enrichment` block. The SDK's `ingestFile()` with `EnrichmentCallbacks` handles the full flow automatically — see [sdk-guide.md](sdk-guide.md#two-phase-pdf-enrichment).
84
86
 
87
+ ### Streaming Progress (NDJSON)
88
+
89
+ For real-time ingestion progress, request NDJSON streaming by setting the `Accept` header or a query parameter:
90
+
91
+ ```bash
92
+ # Via Accept header
93
+ curl -X POST {{ENDPOINT}}/api/memory/ingest/file \
94
+ -H "Authorization: Bearer {{API_KEY}}" \
95
+ -H "Accept: application/x-ndjson" \
96
+ -F "file=@large-report.pdf"
97
+
98
+ # Via query parameter
99
+ curl -X POST "{{ENDPOINT}}/api/memory/ingest/file?stream=true" \
100
+ -H "Authorization: Bearer {{API_KEY}}" \
101
+ -F "file=@large-report.pdf"
102
+ ```
103
+
104
+ The response is streamed as newline-delimited JSON (`Content-Type: application/x-ndjson`). Each line is a JSON object:
105
+
106
+ ```
107
+ {"type":"progress","stage":"parsing","filename":"large-report.pdf","message":"Extracting text..."}
108
+ {"type":"progress","stage":"storing","filename":"large-report.pdf","chunksStored":10,"totalCharacters":4800,"message":"Storing chunk 10..."}
109
+ {"type":"progress","stage":"storing","filename":"large-report.pdf","chunksStored":20,"totalCharacters":9600,"message":"Storing chunk 20..."}
110
+ {"type":"progress","stage":"complete","filename":"large-report.pdf","chunksStored":24,"totalCharacters":11520,"message":"Ingestion complete"}
111
+ {"type":"result","filename":"large-report.pdf","fileType":".pdf","chunks":24,"entryIds":[...],"totalCharacters":11520}
112
+ ```
113
+
114
+ **Progress stages**: `parsing` (text extraction), `storing` (chunk storage — emitted every batch), `enrichment` (PDF image extraction), `complete` (done).
115
+
116
+ The last line always has `"type":"result"` and contains the full `IngestionResult` (same shape as the non-streaming JSON response). On error, the last line has `"type":"error"` with an `error` message string.
117
+
118
+ Without the `Accept: application/x-ndjson` header (or `?stream=true`), the endpoint behaves exactly as before — returning a single JSON response after ingestion completes.
119
+
85
120
  ### Example: ingest a document
86
121
 
87
122
  ```bash
@@ -249,7 +284,7 @@ curl -s -X POST {{ENDPOINT}}/api/memory/ingest \
249
284
  **When to extract**: Always extract when content mentions specific people, tools, technologies, organizations, locations, or events by name. Skip only for abstract observations with no named subjects (e.g., "prefer tabs over spaces").
250
285
 
251
286
  **Entity fields**: `name` (required), `type` (required), `metadata` (optional properties object)
252
- **Relationship fields**: `source` (source entity name), `target` (target entity name), `type` (required)
287
+ **Relationship fields**: `source` (source entity name), `target` (target entity name), `type` (required). Legacy `{from, to}` aliases are also accepted by the pyx-cloud hosted wrapper at `memory.api.pyxmate.com` for backward compatibility, but `{source, target}` is canonical.
253
288
 
254
289
  ---
255
290