@modelprofile.com/flexharness 8.5.0 → 9.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.
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@modelprofile.com/flexharness',
|
|
6
|
-
version: '
|
|
6
|
+
version: '9.1.0',
|
|
7
7
|
description: 'The FlexHarness toolbox source repository and shared dependency catalog.'
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSwrQkFBK0I7SUFDckMsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLDBFQUEwRTtDQUN4RixDQUFBIn0=
|
|
@@ -6,14 +6,18 @@ export interface IDocumentRequestOptions {
|
|
|
6
6
|
/** Passed to the model call unchanged, for example `{ openai: { store: false } }`. */
|
|
7
7
|
providerOptions?: TSmartAiProviderOptions;
|
|
8
8
|
/**
|
|
9
|
-
* Checked before each document is rendered and before the model call, and passed to the
|
|
10
|
-
* call
|
|
9
|
+
* Checked before each document is rendered and before the model call, and passed to both the
|
|
10
|
+
* render and the model call: an abort stops a document that is rendering. The request rejects
|
|
11
|
+
* with the signal's reason.
|
|
11
12
|
*/
|
|
12
13
|
abortSignal?: AbortSignal;
|
|
13
14
|
/**
|
|
14
|
-
* The most rendered pages one request may send to the model
|
|
15
|
-
* with `DocumentPageLimitError` before the model is called
|
|
16
|
-
*
|
|
15
|
+
* The most rendered pages one request may send to the model, counted over all its documents. A
|
|
16
|
+
* request with more pages rejects with `DocumentPageLimitError` before the model is called. Each
|
|
17
|
+
* document is rendered only when its page count fits the pages the request has left, so the
|
|
18
|
+
* document that exceeds the limit and every document after it are not rendered. The exception is
|
|
19
|
+
* a one-page document that comes after the request's pages are used up: it renders and is then
|
|
20
|
+
* refused.
|
|
17
21
|
*/
|
|
18
22
|
maxPages?: number;
|
|
19
23
|
/**
|
|
@@ -53,17 +57,28 @@ export interface IDocumentAnalysisResult {
|
|
|
53
57
|
pageCount: number;
|
|
54
58
|
}
|
|
55
59
|
export interface IDocumentPageLimitErrorDetails {
|
|
60
|
+
/** The pages of the documents up to and including the one that exceeded the limit. */
|
|
56
61
|
renderedPages: number;
|
|
57
62
|
maxPages: number;
|
|
58
63
|
documentCount: number;
|
|
64
|
+
/** Zero-based position, in the request's documents, of the document that exceeded the limit. */
|
|
65
|
+
documentIndex: number;
|
|
66
|
+
/** Whether the pages of every document of the request were counted. */
|
|
59
67
|
allDocumentsRendered: boolean;
|
|
60
68
|
}
|
|
61
|
-
/** A request whose documents
|
|
69
|
+
/** A request whose documents have more pages than its `maxPages`; the model was not called. */
|
|
62
70
|
export declare class DocumentPageLimitError extends Error {
|
|
63
|
-
/**
|
|
71
|
+
/**
|
|
72
|
+
* The pages of the documents up to and including the one that exceeded the limit. That document's
|
|
73
|
+
* pages are counted but not rendered, except a one-page document that came after the request's
|
|
74
|
+
* pages were used up, which rendered and was then refused. Documents after it are neither counted
|
|
75
|
+
* nor rendered.
|
|
76
|
+
*/
|
|
64
77
|
readonly renderedPages: number;
|
|
65
78
|
readonly maxPages: number;
|
|
66
|
-
|
|
79
|
+
/** Zero-based position, in the request's documents, of the document that exceeded the limit. */
|
|
80
|
+
readonly documentIndex: number;
|
|
81
|
+
constructor(details: IDocumentPageLimitErrorDetails, options?: ErrorOptions);
|
|
67
82
|
}
|
|
68
83
|
/** The model-based PDF OCR recipe formerly provided by SmartOCR. */
|
|
69
84
|
export declare function extractTextFromPdf(pdfDocument: Uint8Array, options: IPdfTextExtractionOptions): Promise<string>;
|
|
@@ -14,21 +14,29 @@ function ensureSmartpdf() {
|
|
|
14
14
|
}
|
|
15
15
|
return smartpdfStart;
|
|
16
16
|
}
|
|
17
|
-
/** A request whose documents
|
|
17
|
+
/** A request whose documents have more pages than its `maxPages`; the model was not called. */
|
|
18
18
|
export class DocumentPageLimitError extends Error {
|
|
19
|
-
/**
|
|
19
|
+
/**
|
|
20
|
+
* The pages of the documents up to and including the one that exceeded the limit. That document's
|
|
21
|
+
* pages are counted but not rendered, except a one-page document that came after the request's
|
|
22
|
+
* pages were used up, which rendered and was then refused. Documents after it are neither counted
|
|
23
|
+
* nor rendered.
|
|
24
|
+
*/
|
|
20
25
|
renderedPages;
|
|
21
26
|
maxPages;
|
|
22
|
-
|
|
27
|
+
/** Zero-based position, in the request's documents, of the document that exceeded the limit. */
|
|
28
|
+
documentIndex;
|
|
29
|
+
constructor(details, options) {
|
|
23
30
|
const subject = details.documentCount === 1
|
|
24
31
|
? `The document has ${details.renderedPages} pages`
|
|
25
32
|
: details.allDocumentsRendered
|
|
26
33
|
? `The documents have ${details.renderedPages} pages`
|
|
27
34
|
: `The documents have at least ${details.renderedPages} pages`;
|
|
28
|
-
super(`${subject}, more than the ${details.maxPages} allowed
|
|
35
|
+
super(`${subject}, more than the ${details.maxPages} allowed.`, options);
|
|
29
36
|
this.name = 'DocumentPageLimitError';
|
|
30
37
|
this.renderedPages = details.renderedPages;
|
|
31
38
|
this.maxPages = details.maxPages;
|
|
39
|
+
this.documentIndex = details.documentIndex;
|
|
32
40
|
}
|
|
33
41
|
}
|
|
34
42
|
const DEFAULT_OCR_SYSTEM_MESSAGE = 'You are a precise OCR engine. Extract text faithfully and do not summarize.';
|
|
@@ -66,16 +74,31 @@ export async function analyzeDocumentsWithUsage(options) {
|
|
|
66
74
|
for (const [index, doc] of options.pdfDocuments.entries()) {
|
|
67
75
|
const pdf = await ensureSmartpdf();
|
|
68
76
|
abortSignal?.throwIfAborted();
|
|
69
|
-
const
|
|
77
|
+
const limitDetails = (renderedPages, limit) => ({
|
|
78
|
+
renderedPages,
|
|
79
|
+
maxPages: limit,
|
|
80
|
+
documentCount: options.pdfDocuments.length,
|
|
81
|
+
documentIndex: index,
|
|
82
|
+
allDocumentsRendered: index === options.pdfDocuments.length - 1,
|
|
83
|
+
});
|
|
84
|
+
// SmartPDF limits one document, so each render gets the pages the request has left. It takes
|
|
85
|
+
// no limit of zero: when the earlier documents used up the request's pages, the smallest limit
|
|
86
|
+
// lets the document's page count be known, and a document of one page renders and is refused below.
|
|
87
|
+
const renderMaxPages = maxPages === undefined ? undefined : Math.max(maxPages - imagePages.length, 1);
|
|
88
|
+
let pages;
|
|
89
|
+
try {
|
|
90
|
+
pages = await pdf.convertPDFToPngBytes(doc, { signal: abortSignal, maxPages: renderMaxPages });
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
if (maxPages !== undefined && error instanceof plugins.smartpdf.SmartPdfPageLimitError) {
|
|
94
|
+
throw new DocumentPageLimitError(limitDetails(imagePages.length + error.pageCount, maxPages), { cause: error });
|
|
95
|
+
}
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
70
98
|
abortSignal?.throwIfAborted();
|
|
71
99
|
imagePages.push(...pages);
|
|
72
100
|
if (maxPages !== undefined && imagePages.length > maxPages) {
|
|
73
|
-
throw new DocumentPageLimitError(
|
|
74
|
-
renderedPages: imagePages.length,
|
|
75
|
-
maxPages,
|
|
76
|
-
documentCount: options.pdfDocuments.length,
|
|
77
|
-
allDocumentsRendered: index === options.pdfDocuments.length - 1,
|
|
78
|
-
});
|
|
101
|
+
throw new DocumentPageLimitError(limitDetails(imagePages.length, maxPages));
|
|
79
102
|
}
|
|
80
103
|
}
|
|
81
104
|
// Filter out empty buffers
|
|
@@ -170,4 +193,4 @@ export async function stopSmartpdf() {
|
|
|
170
193
|
}
|
|
171
194
|
await instance.stop();
|
|
172
195
|
}
|
|
173
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
196
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90c19kb2N1bWVudC9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQU14QywrR0FBK0c7QUFDL0csSUFBSSxhQUFhLEdBQThCLElBQUksQ0FBQztBQUVwRCxTQUFTLGNBQWM7SUFDckIsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBQ25CLE1BQU0sUUFBUSxHQUFHLElBQUksT0FBTyxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNqRCxNQUFNLEtBQUssR0FBRyxRQUFRLENBQUMsS0FBSyxFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ3BELGFBQWEsR0FBRyxLQUFLLENBQUM7UUFDdEIsS0FBSyxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUU7WUFDZixJQUFJLGFBQWEsS0FBSyxLQUFLLEVBQUUsQ0FBQztnQkFDNUIsYUFBYSxHQUFHLElBQUksQ0FBQztZQUN2QixDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBQ0QsT0FBTyxhQUFhLENBQUM7QUFDdkIsQ0FBQztBQXlFRCwrRkFBK0Y7QUFDL0YsTUFBTSxPQUFPLHNCQUF1QixTQUFRLEtBQUs7SUFDL0M7Ozs7O09BS0c7SUFDYSxhQUFhLENBQVM7SUFDdEIsUUFBUSxDQUFTO0lBQ2pDLGdHQUFnRztJQUNoRixhQUFhLENBQVM7SUFFdEMsWUFBWSxPQUF1QyxFQUFFLE9BQXNCO1FBQ3pFLE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxhQUFhLEtBQUssQ0FBQztZQUN6QyxDQUFDLENBQUMsb0JBQW9CLE9BQU8sQ0FBQyxhQUFhLFFBQVE7WUFDbkQsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxvQkFBb0I7Z0JBQzVCLENBQUMsQ0FBQyxzQkFBc0IsT0FBTyxDQUFDLGFBQWEsUUFBUTtnQkFDckQsQ0FBQyxDQUFDLCtCQUErQixPQUFPLENBQUMsYUFBYSxRQUFRLENBQUM7UUFDbkUsS0FBSyxDQUFDLEdBQUcsT0FBTyxtQkFBbUIsT0FBTyxDQUFDLFFBQVEsV0FBVyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ3pFLElBQUksQ0FBQyxJQUFJLEdBQUcsd0JBQXdCLENBQUM7UUFDckMsSUFBSSxDQUFDLGFBQWEsR0FBRyxPQUFPLENBQUMsYUFBYSxDQUFDO1FBQzNDLElBQUksQ0FBQyxRQUFRLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQztRQUNqQyxJQUFJLENBQUMsYUFBYSxHQUFHLE9BQU8sQ0FBQyxhQUFhLENBQUM7SUFDN0MsQ0FBQztDQUNGO0FBRUQsTUFBTSwwQkFBMEIsR0FBRyw2RUFBNkUsQ0FBQztBQUNqSCxNQUFNLHdCQUF3QixHQUFHLG1KQUFtSixDQUFDO0FBRXJMLG9FQUFvRTtBQUNwRSxNQUFNLENBQUMsS0FBSyxVQUFVLGtCQUFrQixDQUN0QyxXQUF1QixFQUN2QixPQUFrQztJQUVsQyxPQUFPLENBQUMsTUFBTSwyQkFBMkIsQ0FBQyxXQUFXLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7QUFDeEUsQ0FBQztBQUVELDJGQUEyRjtBQUMzRixNQUFNLENBQUMsS0FBSyxVQUFVLDJCQUEyQixDQUMvQyxXQUF1QixFQUN2QixPQUFrQztJQUVsQyxPQUFPLHlCQUF5QixDQUFDO1FBQy9CLEtBQUssRUFBRSxPQUFPLENBQUMsS0FBSztRQUNwQixhQUFhLEVBQUUsT0FBTyxDQUFDLGFBQWEsSUFBSSwwQkFBMEI7UUFDbEUsV0FBVyxFQUFFLE9BQU8sQ0FBQyxXQUFXLElBQUksd0JBQXdCO1FBQzVELFlBQVksRUFBRSxDQUFDLFdBQVcsQ0FBQztRQUMzQixjQUFjLEVBQUUsT0FBTyxDQUFDLGNBQWM7UUFDdEMsZUFBZSxFQUFFLE9BQU8sQ0FBQyxlQUFlO1FBQ3hDLFdBQVcsRUFBRSxPQUFPLENBQUMsV0FBVztRQUNoQyxRQUFRLEVBQUUsT0FBTyxDQUFDLFFBQVE7UUFDMUIsT0FBTyxFQUFFLE9BQU8sQ0FBQyxPQUFPO0tBQ3pCLENBQUMsQ0FBQztBQUNMLENBQUM7QUFFRCxNQUFNLENBQUMsS0FBSyxVQUFVLGdCQUFnQixDQUFDLE9BQXlCO0lBQzlELE9BQU8sQ0FBQyxNQUFNLHlCQUF5QixDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO0FBQ3pELENBQUM7QUFFRCx5RkFBeUY7QUFDekYsTUFBTSxDQUFDLEtBQUssVUFBVSx5QkFBeUIsQ0FBQyxPQUF5QjtJQUN2RSxNQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsUUFBUSxDQUFDO0lBQ2xDLElBQUksUUFBUSxLQUFLLFNBQVMsSUFBSSxDQUFDLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUMsSUFBSSxRQUFRLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUNoRixNQUFNLElBQUksVUFBVSxDQUFDLDJDQUEyQyxDQUFDLENBQUM7SUFDcEUsQ0FBQztJQUNELE1BQU0sV0FBVyxHQUFHLE9BQU8sQ0FBQyxXQUFXLENBQUM7SUFDeEMsV0FBVyxFQUFFLGNBQWMsRUFBRSxDQUFDO0lBRTlCLE1BQU0sVUFBVSxHQUFpQixFQUFFLENBQUM7SUFDcEMsS0FBSyxNQUFNLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxJQUFJLE9BQU8sQ0FBQyxZQUFZLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQztRQUMxRCxNQUFNLEdBQUcsR0FBRyxNQUFNLGNBQWMsRUFBRSxDQUFDO1FBQ25DLFdBQVcsRUFBRSxjQUFjLEVBQUUsQ0FBQztRQUM5QixNQUFNLFlBQVksR0FBRyxDQUFDLGFBQXFCLEVBQUUsS0FBYSxFQUFrQyxFQUFFLENBQUMsQ0FBQztZQUM5RixhQUFhO1lBQ2IsUUFBUSxFQUFFLEtBQUs7WUFDZixhQUFhLEVBQUUsT0FBTyxDQUFDLFlBQVksQ0FBQyxNQUFNO1lBQzFDLGFBQWEsRUFBRSxLQUFLO1lBQ3BCLG9CQUFvQixFQUFFLEtBQUssS0FBSyxPQUFPLENBQUMsWUFBWSxDQUFDLE1BQU0sR0FBRyxDQUFDO1NBQ2hFLENBQUMsQ0FBQztRQUNILDZGQUE2RjtRQUM3RiwrRkFBK0Y7UUFDL0Ysb0dBQW9HO1FBQ3BHLE1BQU0sY0FBYyxHQUFHLFFBQVEsS0FBSyxTQUFTLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxRQUFRLEdBQUcsVUFBVSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQztRQUN0RyxJQUFJLEtBQW1CLENBQUM7UUFDeEIsSUFBSSxDQUFDO1lBQ0gsS0FBSyxHQUFHLE1BQU0sR0FBRyxDQUFDLG9CQUFvQixDQUFDLEdBQUcsRUFBRSxFQUFFLE1BQU0sRUFBRSxXQUFXLEVBQUUsUUFBUSxFQUFFLGNBQWMsRUFBRSxDQUFDLENBQUM7UUFDakcsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixJQUFJLFFBQVEsS0FBSyxTQUFTLElBQUksS0FBSyxZQUFZLE9BQU8sQ0FBQyxRQUFRLENBQUMsc0JBQXNCLEVBQUUsQ0FBQztnQkFDdkYsTUFBTSxJQUFJLHNCQUFzQixDQUFDLFlBQVksQ0FBQyxVQUFVLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQyxTQUFTLEVBQUUsUUFBUSxDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztZQUNsSCxDQUFDO1lBQ0QsTUFBTSxLQUFLLENBQUM7UUFDZCxDQUFDO1FBQ0QsV0FBVyxFQUFFLGNBQWMsRUFBRSxDQUFDO1FBQzlCLFVBQVUsQ0FBQyxJQUFJLENBQUMsR0FBRyxLQUFLLENBQUMsQ0FBQztRQUMxQixJQUFJLFFBQVEsS0FBSyxTQUFTLElBQUksVUFBVSxDQUFDLE1BQU0sR0FBRyxRQUFRLEVBQUUsQ0FBQztZQUMzRCxNQUFNLElBQUksc0JBQXNCLENBQUMsWUFBWSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQztRQUM5RSxDQUFDO0lBQ0gsQ0FBQztJQUVELDJCQUEyQjtJQUMzQixNQUFNLFVBQVUsR0FBRyxVQUFVLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsSUFBSSxJQUFJLElBQUksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFFdEUsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQztJQUNoQyxNQUFNLFVBQVUsR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLElBQUksT0FBTyxDQUFDLDJCQUEyQixDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztJQUNwRyw2RkFBNkY7SUFDN0YsZ0dBQWdHO0lBQ2hHLE1BQU0sS0FBSyxHQUFHLFVBQVU7UUFDdEIsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQztZQUN4QixLQUFLLEVBQUUsT0FBTyxDQUFDLEtBQUs7WUFDcEIsVUFBVSxFQUFFO2dCQUNWLFlBQVksRUFBRSxLQUFLLEVBQUUsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLEVBQUUsRUFBRTtvQkFDN0MsVUFBVSxDQUFDLEtBQUssRUFBRSxDQUFDO29CQUNuQixJQUFJLENBQUM7d0JBQ0gsT0FBTyxNQUFNLFVBQVUsRUFBRSxDQUFDO29CQUM1QixDQUFDO29CQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7d0JBQ2YsVUFBVSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsV0FBVyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQzt3QkFDdEUsTUFBTSxLQUFLLENBQUM7b0JBQ2QsQ0FBQztnQkFDSCxDQUFDO2FBQ0Y7U0FDRixDQUFDO1FBQ0osQ0FBQyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUM7SUFDbEIsTUFBTSxRQUFRLEdBQW1CO1FBQy9CLEdBQUcsQ0FBQyxPQUFPLENBQUMsY0FBYyxJQUFJLEVBQUUsQ0FBQztRQUNqQztZQUNFLElBQUksRUFBRSxNQUFNO1lBQ1osT0FBTyxFQUFFO2dCQUNQLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsT0FBTyxDQUFDLFdBQVcsRUFBRTtnQkFDM0MsR0FBRyxVQUFVLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztvQkFDekIsSUFBSSxFQUFFLE1BQWU7b0JBQ3JCLElBQUksRUFBRSxJQUFJO29CQUNWLFNBQVMsRUFBRSxXQUFvQjtpQkFDaEMsQ0FBQyxDQUFDO2FBQ0o7U0FDRjtLQUNGLENBQUM7SUFDRixJQUFJLE1BQXdELENBQUM7SUFDN0QsSUFBSSxDQUFDO1FBQ0gsTUFBTSxHQUFHLE1BQU0sT0FBTyxDQUFDLFlBQVksQ0FBQztZQUNsQyxLQUFLO1lBQ0wsWUFBWSxFQUFFLE9BQU8sQ0FBQyxhQUFhO1lBQ25DLFFBQVE7WUFDUixlQUFlLEVBQUUsT0FBTyxDQUFDLGVBQWU7WUFDeEMsV0FBVztZQUNYLEdBQUcsQ0FBQyxVQUFVO2dCQUNaLENBQUMsQ0FBQztvQkFDRSxzQkFBc0IsRUFBRSxDQUFDLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsRUFBRSxFQUFFO3dCQUN4RCxVQUFVLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxTQUFTLENBQUMsQ0FBQztvQkFDckMsQ0FBQztpQkFDRjtnQkFDSCxDQUFDLENBQUMsRUFBRSxDQUFDO1NBQ1IsQ0FBQyxDQUFDO1FBQ0gsVUFBVSxFQUFFLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUNoQyxDQUFDO0lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztRQUNmLFVBQVUsRUFBRSxNQUFNLENBQUMsV0FBVyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNoRSxNQUFNLEtBQUssQ0FBQztJQUNkLENBQUM7SUFDRCxNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsVUFBVSxDQUFDO0lBQ2hDLE1BQU0sV0FBVyxHQUFHLEtBQUssQ0FBQyxXQUFXLElBQUksQ0FBQyxDQUFDO0lBQzNDLE1BQU0sWUFBWSxHQUFHLEtBQUssQ0FBQyxZQUFZLElBQUksQ0FBQyxDQUFDO0lBQzdDLE9BQU87UUFDTCxJQUFJLEVBQUUsTUFBTSxDQUFDLElBQUk7UUFDakIsS0FBSyxFQUFFO1lBQ0wsV0FBVztZQUNYLFlBQVk7WUFDWixXQUFXLEVBQUUsV0FBVyxHQUFHLFlBQVk7WUFDdkMsZUFBZSxFQUFFLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxlQUFlLElBQUksQ0FBQztZQUM3RCxnQkFBZ0IsRUFBRSxLQUFLLENBQUMsaUJBQWlCLENBQUMsZ0JBQWdCLElBQUksQ0FBQztTQUNoRTtRQUNELFNBQVMsRUFBRSxVQUFVLENBQUMsTUFBTTtLQUM3QixDQUFDO0FBQ0osQ0FBQztBQUVELE1BQU0sQ0FBQyxLQUFLLFVBQVUsWUFBWTtJQUNoQyxNQUFNLEtBQUssR0FBRyxhQUFhLENBQUM7SUFDNUIsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ1gsT0FBTztJQUNULENBQUM7SUFDRCxtR0FBbUc7SUFDbkcsMERBQTBEO0lBQzFELGFBQWEsR0FBRyxJQUFJLENBQUM7SUFDckIsSUFBSSxRQUFtQixDQUFDO0lBQ3hCLElBQUksQ0FBQztRQUNILFFBQVEsR0FBRyxNQUFNLEtBQUssQ0FBQztJQUN6QixDQUFDO0lBQUMsTUFBTSxDQUFDO1FBQ1AsZ0VBQWdFO1FBQ2hFLE9BQU87SUFDVCxDQUFDO0lBQ0QsTUFBTSxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUM7QUFDeEIsQ0FBQyJ9
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"author": "Task Venture Capital GmbH",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"name": "@modelprofile.com/flexharness",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "9.1.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"description": "Managed agent sessions with tools, MCP, chat, OCR, documents and browser control through focused subpath imports.",
|
|
8
8
|
"main": "./dist_ts/index.js",
|
|
@@ -62,15 +62,15 @@
|
|
|
62
62
|
}
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
|
-
"@modelprofile.com/flexharness-agent": "
|
|
66
|
-
"@modelprofile.com/flexharness-models": "
|
|
65
|
+
"@modelprofile.com/flexharness-agent": "9.1.0",
|
|
66
|
+
"@modelprofile.com/flexharness-models": "9.1.0",
|
|
67
67
|
"@push.rocks/smartrequest": "^5.0.1",
|
|
68
68
|
"ai": "^7.0.79",
|
|
69
69
|
"zod": "^4.4.1"
|
|
70
70
|
},
|
|
71
71
|
"peerDependencies": {
|
|
72
72
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
73
|
-
"@push.rocks/smartpdf": "^
|
|
73
|
+
"@push.rocks/smartpdf": "^6.0.0",
|
|
74
74
|
"puppeteer": "^24.42.0",
|
|
75
75
|
"ink": "^6.8.0",
|
|
76
76
|
"ink-text-input": "^6.0.0",
|
package/ts/00_commitinfo_data.ts
CHANGED
package/ts_document/index.ts
CHANGED
|
@@ -26,14 +26,18 @@ export interface IDocumentRequestOptions {
|
|
|
26
26
|
/** Passed to the model call unchanged, for example `{ openai: { store: false } }`. */
|
|
27
27
|
providerOptions?: TSmartAiProviderOptions;
|
|
28
28
|
/**
|
|
29
|
-
* Checked before each document is rendered and before the model call, and passed to the
|
|
30
|
-
* call
|
|
29
|
+
* Checked before each document is rendered and before the model call, and passed to both the
|
|
30
|
+
* render and the model call: an abort stops a document that is rendering. The request rejects
|
|
31
|
+
* with the signal's reason.
|
|
31
32
|
*/
|
|
32
33
|
abortSignal?: AbortSignal;
|
|
33
34
|
/**
|
|
34
|
-
* The most rendered pages one request may send to the model
|
|
35
|
-
* with `DocumentPageLimitError` before the model is called
|
|
36
|
-
*
|
|
35
|
+
* The most rendered pages one request may send to the model, counted over all its documents. A
|
|
36
|
+
* request with more pages rejects with `DocumentPageLimitError` before the model is called. Each
|
|
37
|
+
* document is rendered only when its page count fits the pages the request has left, so the
|
|
38
|
+
* document that exceeds the limit and every document after it are not rendered. The exception is
|
|
39
|
+
* a one-page document that comes after the request's pages are used up: it renders and is then
|
|
40
|
+
* refused.
|
|
37
41
|
*/
|
|
38
42
|
maxPages?: number;
|
|
39
43
|
/**
|
|
@@ -78,28 +82,40 @@ export interface IDocumentAnalysisResult {
|
|
|
78
82
|
}
|
|
79
83
|
|
|
80
84
|
export interface IDocumentPageLimitErrorDetails {
|
|
85
|
+
/** The pages of the documents up to and including the one that exceeded the limit. */
|
|
81
86
|
renderedPages: number;
|
|
82
87
|
maxPages: number;
|
|
83
88
|
documentCount: number;
|
|
89
|
+
/** Zero-based position, in the request's documents, of the document that exceeded the limit. */
|
|
90
|
+
documentIndex: number;
|
|
91
|
+
/** Whether the pages of every document of the request were counted. */
|
|
84
92
|
allDocumentsRendered: boolean;
|
|
85
93
|
}
|
|
86
94
|
|
|
87
|
-
/** A request whose documents
|
|
95
|
+
/** A request whose documents have more pages than its `maxPages`; the model was not called. */
|
|
88
96
|
export class DocumentPageLimitError extends Error {
|
|
89
|
-
/**
|
|
97
|
+
/**
|
|
98
|
+
* The pages of the documents up to and including the one that exceeded the limit. That document's
|
|
99
|
+
* pages are counted but not rendered, except a one-page document that came after the request's
|
|
100
|
+
* pages were used up, which rendered and was then refused. Documents after it are neither counted
|
|
101
|
+
* nor rendered.
|
|
102
|
+
*/
|
|
90
103
|
public readonly renderedPages: number;
|
|
91
104
|
public readonly maxPages: number;
|
|
105
|
+
/** Zero-based position, in the request's documents, of the document that exceeded the limit. */
|
|
106
|
+
public readonly documentIndex: number;
|
|
92
107
|
|
|
93
|
-
constructor(details: IDocumentPageLimitErrorDetails) {
|
|
108
|
+
constructor(details: IDocumentPageLimitErrorDetails, options?: ErrorOptions) {
|
|
94
109
|
const subject = details.documentCount === 1
|
|
95
110
|
? `The document has ${details.renderedPages} pages`
|
|
96
111
|
: details.allDocumentsRendered
|
|
97
112
|
? `The documents have ${details.renderedPages} pages`
|
|
98
113
|
: `The documents have at least ${details.renderedPages} pages`;
|
|
99
|
-
super(`${subject}, more than the ${details.maxPages} allowed
|
|
114
|
+
super(`${subject}, more than the ${details.maxPages} allowed.`, options);
|
|
100
115
|
this.name = 'DocumentPageLimitError';
|
|
101
116
|
this.renderedPages = details.renderedPages;
|
|
102
117
|
this.maxPages = details.maxPages;
|
|
118
|
+
this.documentIndex = details.documentIndex;
|
|
103
119
|
}
|
|
104
120
|
}
|
|
105
121
|
|
|
@@ -149,16 +165,30 @@ export async function analyzeDocumentsWithUsage(options: IDocumentOptions): Prom
|
|
|
149
165
|
for (const [index, doc] of options.pdfDocuments.entries()) {
|
|
150
166
|
const pdf = await ensureSmartpdf();
|
|
151
167
|
abortSignal?.throwIfAborted();
|
|
152
|
-
const
|
|
168
|
+
const limitDetails = (renderedPages: number, limit: number): IDocumentPageLimitErrorDetails => ({
|
|
169
|
+
renderedPages,
|
|
170
|
+
maxPages: limit,
|
|
171
|
+
documentCount: options.pdfDocuments.length,
|
|
172
|
+
documentIndex: index,
|
|
173
|
+
allDocumentsRendered: index === options.pdfDocuments.length - 1,
|
|
174
|
+
});
|
|
175
|
+
// SmartPDF limits one document, so each render gets the pages the request has left. It takes
|
|
176
|
+
// no limit of zero: when the earlier documents used up the request's pages, the smallest limit
|
|
177
|
+
// lets the document's page count be known, and a document of one page renders and is refused below.
|
|
178
|
+
const renderMaxPages = maxPages === undefined ? undefined : Math.max(maxPages - imagePages.length, 1);
|
|
179
|
+
let pages: Uint8Array[];
|
|
180
|
+
try {
|
|
181
|
+
pages = await pdf.convertPDFToPngBytes(doc, { signal: abortSignal, maxPages: renderMaxPages });
|
|
182
|
+
} catch (error) {
|
|
183
|
+
if (maxPages !== undefined && error instanceof plugins.smartpdf.SmartPdfPageLimitError) {
|
|
184
|
+
throw new DocumentPageLimitError(limitDetails(imagePages.length + error.pageCount, maxPages), { cause: error });
|
|
185
|
+
}
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
153
188
|
abortSignal?.throwIfAborted();
|
|
154
189
|
imagePages.push(...pages);
|
|
155
190
|
if (maxPages !== undefined && imagePages.length > maxPages) {
|
|
156
|
-
throw new DocumentPageLimitError(
|
|
157
|
-
renderedPages: imagePages.length,
|
|
158
|
-
maxPages,
|
|
159
|
-
documentCount: options.pdfDocuments.length,
|
|
160
|
-
allDocumentsRendered: index === options.pdfDocuments.length - 1,
|
|
161
|
-
});
|
|
191
|
+
throw new DocumentPageLimitError(limitDetails(imagePages.length, maxPages));
|
|
162
192
|
}
|
|
163
193
|
}
|
|
164
194
|
|
package/ts_document/readme.md
CHANGED
|
@@ -26,8 +26,8 @@ Supply a model from your selected FlexHarness provider. `extractTextFromPdf` rep
|
|
|
26
26
|
Both functions accept four request options:
|
|
27
27
|
|
|
28
28
|
- `providerOptions` is passed to the model call unchanged, for example `{ openai: { store: false } }` so the provider does not keep the request as application state.
|
|
29
|
-
- `abortSignal` is checked before each document is rendered and before the model call, and is passed to the model call
|
|
30
|
-
- `maxPages` is the most rendered pages one request may send to the model. A request with more pages rejects with `DocumentPageLimitError`
|
|
29
|
+
- `abortSignal` is checked before each document is rendered and before the model call, and is passed to both the render and the model call, so an abort also stops a document that is rendering. The request rejects with the signal's reason.
|
|
30
|
+
- `maxPages` is the most rendered pages one request may send to the model, counted over all its documents. A request with more pages rejects with `DocumentPageLimitError` before the model is called. Each document is rendered only when its page count fits the pages the request has left, so the document that exceeds the limit and every document after it are not rendered; SmartPDF counts that document's pages without rendering them. The exception is a one-page document that comes after the request's pages are used up: SmartPDF takes no limit of zero pages, so that document renders and is then refused. The error carries `renderedPages` (the pages of the documents up to and including the one that exceeded the limit), `maxPages` and `documentIndex` (the zero-based position of that document), and SmartPDF's `SmartPdfPageLimitError` as its `cause` when SmartPDF refused the document.
|
|
31
31
|
- `onUsage` receives the usage of each model call of the request, also of a request that fails or is aborted; see [Usage of a request that fails or is aborted](#usage-of-a-request-that-fails-or-is-aborted).
|
|
32
32
|
|
|
33
33
|
`extractTextFromPdfWithUsage` and `analyzeDocumentsWithUsage` take the same arguments and return `{ text, usage, pageCount }`. `usage` has the shape of an agent run's usage (`inputTokens`, `outputTokens`, `totalTokens`, `cacheReadTokens`, `cacheWriteTokens`), summed over the request's model steps, with usage the provider leaves out counted as zero; `pageCount` is the number of rendered pages sent to the model.
|