@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: '8.5.0',
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 model
10
- * call. SmartPDF cannot stop a document it is rendering, so that render finishes first.
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. A request with more pages rejects
15
- * with `DocumentPageLimitError` before the model is called; documents after the one that
16
- * exceeded the limit are not rendered.
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 render to more pages than its `maxPages`; the model was not called. */
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
- /** Pages rendered before the request stopped; with several documents, later documents are not counted. */
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
- constructor(details: IDocumentPageLimitErrorDetails);
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 render to more pages than its `maxPages`; the model was not called. */
17
+ /** A request whose documents have more pages than its `maxPages`; the model was not called. */
18
18
  export class DocumentPageLimitError extends Error {
19
- /** Pages rendered before the request stopped; with several documents, later documents are not counted. */
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
- constructor(details) {
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 pages = await pdf.convertPDFToPngBytes(doc);
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90c19kb2N1bWVudC9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQU14QywrR0FBK0c7QUFDL0csSUFBSSxhQUFhLEdBQThCLElBQUksQ0FBQztBQUVwRCxTQUFTLGNBQWM7SUFDckIsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBQ25CLE1BQU0sUUFBUSxHQUFHLElBQUksT0FBTyxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNqRCxNQUFNLEtBQUssR0FBRyxRQUFRLENBQUMsS0FBSyxFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ3BELGFBQWEsR0FBRyxLQUFLLENBQUM7UUFDdEIsS0FBSyxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUU7WUFDZixJQUFJLGFBQWEsS0FBSyxLQUFLLEVBQUUsQ0FBQztnQkFDNUIsYUFBYSxHQUFHLElBQUksQ0FBQztZQUN2QixDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBQ0QsT0FBTyxhQUFhLENBQUM7QUFDdkIsQ0FBQztBQWlFRCxvR0FBb0c7QUFDcEcsTUFBTSxPQUFPLHNCQUF1QixTQUFRLEtBQUs7SUFDL0MsMEdBQTBHO0lBQzFGLGFBQWEsQ0FBUztJQUN0QixRQUFRLENBQVM7SUFFakMsWUFBWSxPQUF1QztRQUNqRCxNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsYUFBYSxLQUFLLENBQUM7WUFDekMsQ0FBQyxDQUFDLG9CQUFvQixPQUFPLENBQUMsYUFBYSxRQUFRO1lBQ25ELENBQUMsQ0FBQyxPQUFPLENBQUMsb0JBQW9CO2dCQUM1QixDQUFDLENBQUMsc0JBQXNCLE9BQU8sQ0FBQyxhQUFhLFFBQVE7Z0JBQ3JELENBQUMsQ0FBQywrQkFBK0IsT0FBTyxDQUFDLGFBQWEsUUFBUSxDQUFD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
196
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90c19kb2N1bWVudC9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQU14QywrR0FBK0c7QUFDL0csSUFBSSxhQUFhLEdBQThCLElBQUksQ0FBQztBQUVwRCxTQUFTLGNBQWM7SUFDckIsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBQ25CLE1BQU0sUUFBUSxHQUFHLElBQUksT0FBTyxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNqRCxNQUFNLEtBQUssR0FBRyxRQUFRLENBQUMsS0FBSyxFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ3BELGFBQWEsR0FBRyxLQUFLLENBQUM7UUFDdEIsS0FBSyxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUU7WUFDZixJQUFJLGFBQWEsS0FBSyxLQUFLLEVBQUUsQ0FBQztnQkFDNUIsYUFBYSxHQUFHLElBQUksQ0FBQztZQUN2QixDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBQ0QsT0FBTyxhQUFhLENBQUM7QUFDdkIsQ0FBQztBQXlFRCwrRkFBK0Y7QUFDL0YsTUFBTSxPQUFPLHNCQUF1QixTQUFRLEtBQUs7SUFDL0M7Ozs7O09BS0c7SUFDYSxhQUFhLENBQVM7SUFDdEIsUUFBUSxDQUFTO0lBQ2pDLGdHQUFnRztJQUNoRixhQUFhLENBQVM7SUFFdEMsWUFBWSxPQUF1QyxFQUFFLE9BQXNCO1FBQ3pFLE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxhQUFhLEtBQUssQ0FBQztZQUN6QyxDQUFDLENBQUMsb0JBQW9CLE9BQU8sQ0FBQyxhQUFhLFFBQVE7WUFDbkQsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxvQkFBb0I7Z0JBQzVCLENBQUMsQ0FBQyxzQkFBc0IsT0FBTyxDQUFDLGFBQWEsUUFBUTtnQkFDckQs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
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": "8.5.0",
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": "8.5.0",
66
- "@modelprofile.com/flexharness-models": "8.5.0",
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": "^5.0.1",
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",
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@modelprofile.com/flexharness',
6
- version: '8.5.0',
6
+ version: '9.1.0',
7
7
  description: 'The FlexHarness toolbox source repository and shared dependency catalog.'
8
8
  }
@@ -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 model
30
- * call. SmartPDF cannot stop a document it is rendering, so that render finishes first.
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. A request with more pages rejects
35
- * with `DocumentPageLimitError` before the model is called; documents after the one that
36
- * exceeded the limit are not rendered.
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 render to more pages than its `maxPages`; the model was not called. */
95
+ /** A request whose documents have more pages than its `maxPages`; the model was not called. */
88
96
  export class DocumentPageLimitError extends Error {
89
- /** Pages rendered before the request stopped; with several documents, later documents are not counted. */
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 pages = await pdf.convertPDFToPngBytes(doc);
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
 
@@ -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. SmartPDF cannot stop a document it is already rendering, so that render finishes first.
30
- - `maxPages` is the most rendered pages one request may send to the model. A request with more pages rejects with `DocumentPageLimitError` (`renderedPages`, `maxPages`) before the model is called, and documents after the one that exceeded the limit are not rendered.
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.