@pyxmate/memory 0.10.0 → 0.11.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.
|
@@ -112,21 +112,36 @@ var MemoryClient = class {
|
|
|
112
112
|
* With enrichment callbacks: fetches extracted images, calls describeImage for each,
|
|
113
113
|
* optionally extracts entities, then submits enrichment data back to the server.
|
|
114
114
|
*/
|
|
115
|
+
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: two-phase enrichment fans out across image-describe + entity-extract + v1/v2 negotiation; each branch maps to a documented case in memory-client-enrichment.test.ts
|
|
115
116
|
async ingestFile(file, options) {
|
|
116
117
|
const formData = new FormData();
|
|
117
118
|
formData.append("file", file);
|
|
118
119
|
if (options?.description) {
|
|
119
120
|
formData.append("description", options.description);
|
|
120
121
|
}
|
|
122
|
+
const wantsTextWindows = Boolean(
|
|
123
|
+
options?.enrichment?.extractEntities || options?.enrichment?.extractEntitiesV2
|
|
124
|
+
);
|
|
125
|
+
const headers = { ...this._authHeaders };
|
|
126
|
+
if (wantsTextWindows) {
|
|
127
|
+
headers["X-Pyx-Enrichment-Capabilities"] = "text_windows_v1";
|
|
128
|
+
}
|
|
121
129
|
const res = await fetch(`${this.baseUrl}/api/memory/ingest/file`, {
|
|
122
130
|
method: "POST",
|
|
123
131
|
body: formData,
|
|
124
|
-
headers
|
|
132
|
+
headers
|
|
125
133
|
});
|
|
126
134
|
const result = await this.parseApiResponse(res);
|
|
127
|
-
if (result.enrichment
|
|
128
|
-
|
|
129
|
-
|
|
135
|
+
if (!result.enrichment || !options?.enrichment) {
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
138
|
+
const enrichment = result.enrichment;
|
|
139
|
+
const { fileId, token, expiresAt, images } = enrichment;
|
|
140
|
+
const isV2 = "version" in enrichment;
|
|
141
|
+
const textWindows = isV2 ? enrichment.textWindows : [];
|
|
142
|
+
const descriptions = [];
|
|
143
|
+
const describeImage = options.enrichment.describeImage;
|
|
144
|
+
if (describeImage && images.length > 0) {
|
|
130
145
|
const CONCURRENCY = 5;
|
|
131
146
|
for (let i = 0; i < images.length; i += CONCURRENCY) {
|
|
132
147
|
const batch = images.slice(i, i + CONCURRENCY);
|
|
@@ -143,48 +158,66 @@ var MemoryClient = class {
|
|
|
143
158
|
);
|
|
144
159
|
}
|
|
145
160
|
const imageBuffer = await imageRes.arrayBuffer();
|
|
146
|
-
const description = await
|
|
161
|
+
const description = await describeImage(imageBuffer, imageMeta);
|
|
147
162
|
return { imageId: imageMeta.imageId, description };
|
|
148
163
|
})
|
|
149
164
|
);
|
|
150
165
|
descriptions.push(...batchResults);
|
|
151
166
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
167
|
+
}
|
|
168
|
+
let entities;
|
|
169
|
+
let relationships;
|
|
170
|
+
const v2Callback = options.enrichment.extractEntitiesV2;
|
|
171
|
+
const legacyCallback = options.enrichment.extractEntities;
|
|
172
|
+
const imageDescriptionTexts = descriptions.map((d) => d.description);
|
|
173
|
+
if (v2Callback && (textWindows.length > 0 || imageDescriptionTexts.length > 0)) {
|
|
174
|
+
const extracted = await v2Callback({
|
|
175
|
+
textWindows,
|
|
176
|
+
imageDescriptions: imageDescriptionTexts,
|
|
177
|
+
mimeType: file.type,
|
|
178
|
+
filename: file.name
|
|
179
|
+
});
|
|
180
|
+
entities = extracted.entities;
|
|
181
|
+
relationships = extracted.relationships;
|
|
182
|
+
} else if (legacyCallback) {
|
|
183
|
+
const allInputs = [...textWindows, ...imageDescriptionTexts];
|
|
184
|
+
if (allInputs.length > 0) {
|
|
185
|
+
const extracted = await legacyCallback(allInputs);
|
|
158
186
|
entities = extracted.entities;
|
|
159
187
|
relationships = extracted.relationships;
|
|
160
188
|
}
|
|
161
|
-
const enrichTokenHeader = `${token}:${expiresAt}`;
|
|
162
|
-
const enrichRes = await fetch(`${this.baseUrl}/api/memory/files/${fileId}/enrich`, {
|
|
163
|
-
method: "POST",
|
|
164
|
-
headers: {
|
|
165
|
-
"Content-Type": "application/json",
|
|
166
|
-
"X-Enrichment-Token": enrichTokenHeader,
|
|
167
|
-
...this._authHeaders
|
|
168
|
-
},
|
|
169
|
-
body: JSON.stringify({
|
|
170
|
-
imageDescriptions: descriptions,
|
|
171
|
-
entities,
|
|
172
|
-
relationships
|
|
173
|
-
})
|
|
174
|
-
});
|
|
175
|
-
if (!enrichRes.ok) {
|
|
176
|
-
const body = await enrichRes.json().catch(() => ({}));
|
|
177
|
-
throw new MemoryServerError(
|
|
178
|
-
body.error ?? `Enrichment failed: ${enrichRes.status}`,
|
|
179
|
-
enrichRes.status
|
|
180
|
-
);
|
|
181
|
-
}
|
|
182
|
-
const enrichData = await this.parseApiResponse(enrichRes);
|
|
183
|
-
const enrichCharacters = descriptions.reduce((sum, d) => sum + d.description.length, 0);
|
|
184
|
-
result.entryIds.push(...enrichData.entryIds);
|
|
185
|
-
result.chunks += descriptions.length;
|
|
186
|
-
result.totalCharacters += enrichCharacters;
|
|
187
189
|
}
|
|
190
|
+
const hasGraph = (entities?.length ?? 0) > 0;
|
|
191
|
+
const hasImages = descriptions.length > 0;
|
|
192
|
+
if (!hasGraph && !hasImages) {
|
|
193
|
+
return result;
|
|
194
|
+
}
|
|
195
|
+
const enrichTokenHeader = `${token}:${expiresAt}`;
|
|
196
|
+
const enrichRes = await fetch(`${this.baseUrl}/api/memory/files/${fileId}/enrich`, {
|
|
197
|
+
method: "POST",
|
|
198
|
+
headers: {
|
|
199
|
+
"Content-Type": "application/json",
|
|
200
|
+
"X-Enrichment-Token": enrichTokenHeader,
|
|
201
|
+
...this._authHeaders
|
|
202
|
+
},
|
|
203
|
+
body: JSON.stringify({
|
|
204
|
+
imageDescriptions: descriptions,
|
|
205
|
+
entities,
|
|
206
|
+
relationships
|
|
207
|
+
})
|
|
208
|
+
});
|
|
209
|
+
if (!enrichRes.ok) {
|
|
210
|
+
const body = await enrichRes.json().catch(() => ({}));
|
|
211
|
+
throw new MemoryServerError(
|
|
212
|
+
body.error ?? `Enrichment failed: ${enrichRes.status}`,
|
|
213
|
+
enrichRes.status
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
const enrichData = await this.parseApiResponse(enrichRes);
|
|
217
|
+
const enrichCharacters = descriptions.reduce((sum, d) => sum + d.description.length, 0);
|
|
218
|
+
result.entryIds.push(...enrichData.entryIds);
|
|
219
|
+
result.chunks += descriptions.length;
|
|
220
|
+
result.totalCharacters += enrichCharacters;
|
|
188
221
|
return result;
|
|
189
222
|
}
|
|
190
223
|
/**
|
package/dist/dashboard.mjs
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -71,15 +71,50 @@ interface ExtendedMemoryInterface extends MemoryInterface {
|
|
|
71
71
|
deleteBySource(source: string): Promise<number>;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
/**
|
|
74
|
+
/**
|
|
75
|
+
* Callbacks for two-phase file enrichment. All callbacks are optional so the
|
|
76
|
+
* SDK can support every combination of the v2 flow:
|
|
77
|
+
* - Image-rich PDF + describeImage only → describes images, no entity extraction
|
|
78
|
+
* - Image-rich PDF + describeImage + extractEntities[V2] → describes + extracts
|
|
79
|
+
* - Text-only file + extractEntities[V2] only → extracts from textWindows
|
|
80
|
+
* - Mixed file + all three → describes + extracts from both sources
|
|
81
|
+
*
|
|
82
|
+
* Without ANY callback, ingestFile returns the parsed result without running
|
|
83
|
+
* Phase 2/3 — caller opted out of enrichment entirely.
|
|
84
|
+
*/
|
|
75
85
|
interface EnrichmentCallbacks {
|
|
76
|
-
/**
|
|
77
|
-
|
|
78
|
-
|
|
86
|
+
/**
|
|
87
|
+
* Describe an image using LLM vision. Receives the raw image buffer and
|
|
88
|
+
* metadata. Required for image-bearing files; safe to omit for text-only
|
|
89
|
+
* uploads where the server emits zero images.
|
|
90
|
+
*/
|
|
91
|
+
describeImage?: (imageBuffer: ArrayBuffer, meta: ExtractedImageMeta) => Promise<string>;
|
|
92
|
+
/**
|
|
93
|
+
* Legacy entity-extraction callback. Receives a flat string array which
|
|
94
|
+
* the SDK constructs as `[...textWindows, ...imageDescriptions]` — callers
|
|
95
|
+
* cannot distinguish the two sources. Kept for backwards compatibility;
|
|
96
|
+
* new code should prefer {@link extractEntitiesV2}.
|
|
97
|
+
*/
|
|
79
98
|
extractEntities?: (descriptions: string[]) => Promise<{
|
|
80
99
|
entities: IngestEntity$1[];
|
|
81
100
|
relationships: IngestRelationship$1[];
|
|
82
101
|
}>;
|
|
102
|
+
/**
|
|
103
|
+
* v2 entity-extraction callback. Receives text windows and image
|
|
104
|
+
* descriptions separately so callers can apply different prompts per
|
|
105
|
+
* source. Takes precedence over {@link extractEntities} when both are
|
|
106
|
+
* defined. Triggers the `X-Pyx-Enrichment-Capabilities: text_windows_v1`
|
|
107
|
+
* negotiation header on ingest.
|
|
108
|
+
*/
|
|
109
|
+
extractEntitiesV2?: (input: {
|
|
110
|
+
textWindows: string[];
|
|
111
|
+
imageDescriptions: string[];
|
|
112
|
+
mimeType: string;
|
|
113
|
+
filename: string;
|
|
114
|
+
}) => Promise<{
|
|
115
|
+
entities: IngestEntity$1[];
|
|
116
|
+
relationships: IngestRelationship$1[];
|
|
117
|
+
}>;
|
|
83
118
|
}
|
|
84
119
|
/** Error thrown by MemoryClient when the server returns a non-success response. */
|
|
85
120
|
declare class MemoryServerError extends Error {
|
package/dist/index.mjs
CHANGED
package/dist/react.mjs
CHANGED
|
@@ -11,8 +11,8 @@ import {
|
|
|
11
11
|
toGraphologyFormat,
|
|
12
12
|
transformGraphData,
|
|
13
13
|
unreachableHealth
|
|
14
|
-
} from "./chunk-
|
|
15
|
-
import "./chunk-
|
|
14
|
+
} from "./chunk-DGVOXKYV.mjs";
|
|
15
|
+
import "./chunk-5IERAVVW.mjs";
|
|
16
16
|
|
|
17
17
|
// ../dashboard/src/hooks/use-consolidation-log.ts
|
|
18
18
|
import { useCallback as useCallback2, useMemo } from "react";
|