@burdenoff/fe-libs 2026.904.2 → 2026.904.4
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/dist/shared/assistant/attachments.d.ts +340 -0
- package/dist/shared/assistant/attachments.d.ts.map +1 -0
- package/dist/shared/assistant/attachments.js +370 -0
- package/dist/shared/assistant/conversation.d.ts +153 -0
- package/dist/shared/assistant/conversation.d.ts.map +1 -0
- package/dist/shared/assistant/documentText.d.ts +261 -0
- package/dist/shared/assistant/documentText.d.ts.map +1 -0
- package/dist/shared/assistant/documentText.js +235 -0
- package/dist/shared/assistant/gatewayLimits.d.ts +25 -0
- package/dist/shared/assistant/gatewayLimits.d.ts.map +1 -0
- package/dist/shared/assistant/gatewayLimits.js +4 -0
- package/dist/shared/assistant/index.d.ts +6 -0
- package/dist/shared/assistant/index.d.ts.map +1 -1
- package/dist/shared/assistant/store.d.ts +114 -0
- package/dist/shared/assistant/store.d.ts.map +1 -0
- package/dist/shared/assistant/store.js +198 -0
- package/dist/shared/assistant/turnState.d.ts +16 -0
- package/dist/shared/assistant/turnState.d.ts.map +1 -0
- package/dist/shared/assistant/turnState.js +6 -0
- package/dist/shared/config/authBridgeUrls.d.ts.map +1 -1
- package/dist/shared/config/authBridgeUrls.js +16 -15
- package/dist/shared/config/gatewayUrls.d.ts +29 -0
- package/dist/shared/config/gatewayUrls.d.ts.map +1 -1
- package/dist/shared/config/gatewayUrls.js +44 -20
- package/dist/shared/config/index.d.ts.map +1 -1
- package/dist/shared/native/capacitor.d.ts +49 -0
- package/dist/shared/native/capacitor.d.ts.map +1 -0
- package/dist/shared/native/capacitor.js +31 -0
- package/dist/shared/native/index.d.ts +2 -0
- package/dist/shared/native/index.d.ts.map +1 -1
- package/dist/shared/providers/shell/MultiGatewayProvider.d.ts.map +1 -1
- package/dist/shared/providers/shell/MultiGatewayProvider.js +101 -100
- package/dist/shared/utils/authCookie.d.ts.map +1 -1
- package/dist/shared/utils/authCookie.js +35 -34
- package/dist/shared/utils/gatewayFetchRewrite.d.ts.map +1 -1
- package/dist/shared/utils/gatewayFetchRewrite.js +95 -87
- package/dist/shared-assistant.js +6 -1
- package/dist/shared-config.js +9 -1
- package/dist/shared-native.js +23 -22
- package/dist/shared.js +124 -123
- package/package.json +2 -2
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turning a PDF / DOCX / XLSX into plain text — the PURE half (BOFF-6291).
|
|
3
|
+
*
|
|
4
|
+
* Everything in this file is a string-in/string-out function with no imports,
|
|
5
|
+
* no DOM and no parser dependency, which is what makes it testable under the
|
|
6
|
+
* repo's `environment: 'node'` vitest config. The browser-only half — reading
|
|
7
|
+
* the File, lazily importing pdf.js / fflate, unzipping — lives in
|
|
8
|
+
* `documentExtract.ts` and calls into here.
|
|
9
|
+
*
|
|
10
|
+
* ## Why regex and not DOMParser
|
|
11
|
+
*
|
|
12
|
+
* DOCX and XLSX are ZIPs of XML, and the obvious tool is `DOMParser`. It is
|
|
13
|
+
* browser-only, so every one of these functions would then be untestable here
|
|
14
|
+
* and the extraction logic would ship unverified. We are pulling *text* out of
|
|
15
|
+
* a machine-generated, schema-fixed document part — not rendering untrusted
|
|
16
|
+
* markup — so a targeted scan over the tags Word/Excel actually emit is both
|
|
17
|
+
* sufficient and checkable. The output is inlined into a prompt as text; it is
|
|
18
|
+
* never interpreted as markup, so a mis-parse costs fidelity, not safety.
|
|
19
|
+
*/
|
|
20
|
+
/** Upper bound on characters pulled out of one document before we stop. */
|
|
21
|
+
export declare const MAX_EXTRACTED_CHARS = 200000;
|
|
22
|
+
/** Upper bound on PDF pages we will even look at, however long the document. */
|
|
23
|
+
export declare const MAX_PDF_PAGES_SCANNED = 100;
|
|
24
|
+
/**
|
|
25
|
+
* How many characters of PAGE-SPECIFIC text a page must yield before we are
|
|
26
|
+
* willing to say we read it.
|
|
27
|
+
*
|
|
28
|
+
* A scanned page is not empty — its scanner stamps a footer on every page, and
|
|
29
|
+
* `page.trim() !== ''` is therefore true for a document containing no readable
|
|
30
|
+
* content whatsoever. 24 characters is below any real page of a soil report or
|
|
31
|
+
* an audit (those run to thousands) and above the watermarks that defeat an
|
|
32
|
+
* all-or-nothing check.
|
|
33
|
+
*/
|
|
34
|
+
export declare const MIN_PAGE_TEXT_CHARS = 24;
|
|
35
|
+
/**
|
|
36
|
+
* A line repeated on at least this share of pages is a running head/footer or a
|
|
37
|
+
* scanner watermark, not content.
|
|
38
|
+
*
|
|
39
|
+
* Used ONLY to judge whether a page carries its own text; the line is never
|
|
40
|
+
* removed from the text handed to the model. So a false positive here costs
|
|
41
|
+
* nothing but a slightly more cautious disclosure, while a false negative is the
|
|
42
|
+
* failure this whole notion exists to stop.
|
|
43
|
+
*/
|
|
44
|
+
export declare const BOILERPLATE_PAGE_SHARE = 0.6;
|
|
45
|
+
/**
|
|
46
|
+
* Boilerplate detection only ever applies to short lines, never to content.
|
|
47
|
+
*
|
|
48
|
+
* Named trade-off: a running footer LONGER than this — a full confidentiality
|
|
49
|
+
* paragraph stamped on every page of a scan — is not recognised, and the scan
|
|
50
|
+
* is then treated as readable. That is the safe direction to be wrong in only
|
|
51
|
+
* because the model still sees exactly the text the file contains; it is not a
|
|
52
|
+
* claim the heuristic is exact.
|
|
53
|
+
*/
|
|
54
|
+
export declare const MAX_BOILERPLATE_LINE_CHARS = 80;
|
|
55
|
+
/**
|
|
56
|
+
* Below this share of pages carrying a text layer, a document is "mostly
|
|
57
|
+
* images" and must be presented as unread rather than as extracted.
|
|
58
|
+
*/
|
|
59
|
+
export declare const MIN_TEXT_PAGE_SHARE = 0.5;
|
|
60
|
+
/**
|
|
61
|
+
* What happened when we tried to read a document.
|
|
62
|
+
*
|
|
63
|
+
* Every value other than `ok` MUST reach the model as a sentence — a document
|
|
64
|
+
* we could not read has to look different from a document that was empty, and
|
|
65
|
+
* both have to look different from one we never tried. Silence here is what
|
|
66
|
+
* makes an assistant answer confidently about a file it never saw.
|
|
67
|
+
*/
|
|
68
|
+
export type DocumentExtractionStatus = "ok" | "no-text" | "encrypted" | "corrupt"
|
|
69
|
+
/** No extractor for this type — we did not even try. */
|
|
70
|
+
| "unsupported";
|
|
71
|
+
/** Document formats we can turn into text in the browser. */
|
|
72
|
+
export type DocumentFormat = "pdf" | "docx" | "xlsx";
|
|
73
|
+
export interface DocumentExtraction {
|
|
74
|
+
status: DocumentExtractionStatus;
|
|
75
|
+
/**
|
|
76
|
+
* Which extractor produced this. Carried so the failure wording can be
|
|
77
|
+
* true rather than merely plausible: "appears to be scanned images" is the
|
|
78
|
+
* right sentence for a PDF and a wrong one for an empty .docx.
|
|
79
|
+
*/
|
|
80
|
+
format?: DocumentFormat;
|
|
81
|
+
/** Total pages in a PDF (not how many we read — see `pagesScanned`). */
|
|
82
|
+
pageCount?: number;
|
|
83
|
+
/** How many pages we actually looked at; capped by MAX_PDF_PAGES_SCANNED. */
|
|
84
|
+
pagesScanned?: number;
|
|
85
|
+
/** How far into the document `textContent` reaches: pages 1..N were processed. */
|
|
86
|
+
pagesIncluded?: number;
|
|
87
|
+
/**
|
|
88
|
+
* The 1-indexed pages whose text is ACTUALLY in `textContent`.
|
|
89
|
+
*
|
|
90
|
+
* Distinct from `pagesIncluded` on purpose: a 40-page certificate with 3 text
|
|
91
|
+
* pages and 37 image pages processes all 40 and reads 3, and saying "40 pages"
|
|
92
|
+
* there is the exact falsehood this feature must not tell.
|
|
93
|
+
*/
|
|
94
|
+
pageNumbers?: number[];
|
|
95
|
+
/**
|
|
96
|
+
* The 1-indexed pages within `pagesScanned` that yielded no page-specific
|
|
97
|
+
* text — image or blank pages. Counted so they can be DISCLOSED rather than
|
|
98
|
+
* silently folded into a page total.
|
|
99
|
+
*/
|
|
100
|
+
imagePages?: number[];
|
|
101
|
+
/** How many scanned pages carried a text layer at all. */
|
|
102
|
+
textPageCount?: number;
|
|
103
|
+
/** Characters of text the document yielded before the inline budget cut it. */
|
|
104
|
+
sourceChars?: number;
|
|
105
|
+
/** Worksheet names, in workbook order. XLSX only. */
|
|
106
|
+
sheetNames?: string[];
|
|
107
|
+
/** Parser detail for the `corrupt` case — shown to the model verbatim. */
|
|
108
|
+
detail?: string;
|
|
109
|
+
}
|
|
110
|
+
/** Resolve the five XML entities plus numeric character references. */
|
|
111
|
+
export declare function decodeXmlEntities(value: string): string;
|
|
112
|
+
/**
|
|
113
|
+
* `word/document.xml` → plain text.
|
|
114
|
+
*
|
|
115
|
+
* Word's body is a flat list of `<w:p>` paragraphs holding `<w:t>` runs, with
|
|
116
|
+
* `<w:tab/>` and `<w:br/>` as explicit whitespace. Table cells are paragraphs
|
|
117
|
+
* too, so a table comes out one cell per line — lossy for layout, faithful for
|
|
118
|
+
* content, and the model reads it fine.
|
|
119
|
+
*
|
|
120
|
+
* `<w:instrText>` (field codes such as a HYPERLINK target or a MERGEFIELD name)
|
|
121
|
+
* is deliberately skipped: it is markup the reader never sees, and inlining it
|
|
122
|
+
* puts strings in front of the model that are not in the document.
|
|
123
|
+
*/
|
|
124
|
+
export declare function docxXmlToText(xml: string): string;
|
|
125
|
+
/** `xl/sharedStrings.xml` → the string table, indexed as the sheets index it. */
|
|
126
|
+
export declare function parseSharedStrings(xml: string): string[];
|
|
127
|
+
/** `A` → 0, `Z` → 25, `AA` → 26. Returns -1 for anything that is not a column. */
|
|
128
|
+
export declare function columnLetterToIndex(reference: string): number;
|
|
129
|
+
/**
|
|
130
|
+
* One worksheet's XML → CSV-ish rows.
|
|
131
|
+
*
|
|
132
|
+
* Sparse cells are padded from their `r="C7"` reference so column alignment
|
|
133
|
+
* survives, which is the whole reason a spreadsheet is worth inlining at all.
|
|
134
|
+
* Numbers come out exactly as stored — an Excel date is a serial number, and
|
|
135
|
+
* guessing at a display format would put dates in front of the model that the
|
|
136
|
+
* file does not contain.
|
|
137
|
+
*/
|
|
138
|
+
export declare function sheetXmlToRows(xml: string, sharedStrings: string[]): string[];
|
|
139
|
+
/**
|
|
140
|
+
* `xl/workbook.xml` (+ its rels) → the sheets in workbook order.
|
|
141
|
+
*
|
|
142
|
+
* The rels file is what maps `r:id="rId3"` to `worksheets/sheet1.xml`; the
|
|
143
|
+
* common assumption that `sheetN.xml` matches tab order is simply false in any
|
|
144
|
+
* workbook whose sheets have been reordered or deleted.
|
|
145
|
+
*/
|
|
146
|
+
export declare function parseWorkbookSheets(workbookXml: string, relsXml: string): {
|
|
147
|
+
name: string;
|
|
148
|
+
path: string | null;
|
|
149
|
+
}[];
|
|
150
|
+
/** Stitch the parsed sheets into one document, headed by the sheet name. */
|
|
151
|
+
export declare function joinSheets(sheets: {
|
|
152
|
+
name: string;
|
|
153
|
+
rows: string[];
|
|
154
|
+
}[]): string;
|
|
155
|
+
/**
|
|
156
|
+
* pdf.js text items → one page of text.
|
|
157
|
+
*
|
|
158
|
+
* `hasEOL` is pdf.js' own end-of-line marker, so line structure comes from the
|
|
159
|
+
* library rather than from us guessing at coordinates. Marked-content items
|
|
160
|
+
* carry no `str` and are skipped.
|
|
161
|
+
*/
|
|
162
|
+
export declare function pdfTextItemsToPage(items: {
|
|
163
|
+
str?: string;
|
|
164
|
+
hasEOL?: boolean;
|
|
165
|
+
}[]): string;
|
|
166
|
+
/** Header a page gets when several of them are inlined together. */
|
|
167
|
+
export declare function pageMarker(pageNumber: number): string;
|
|
168
|
+
/**
|
|
169
|
+
* Which pages of a PDF actually carry text, and which are images.
|
|
170
|
+
*
|
|
171
|
+
* ## Why an all-or-nothing check is not enough
|
|
172
|
+
*
|
|
173
|
+
* The obvious test — "did ANY page yield a non-empty string" — is defeated by
|
|
174
|
+
* every scanner on the market, because scanners stamp a text footer onto each
|
|
175
|
+
* page image. A 12-page scanned soil report whose only text layer is
|
|
176
|
+
* `Scanned with CamScanner 1` passes that test, and the document is then handed
|
|
177
|
+
* to the model as `Extracted text (12 pages):` with no hint that not one word of
|
|
178
|
+
* the report is in it. The model answers confidently about a file nobody read.
|
|
179
|
+
*
|
|
180
|
+
* So the unit of judgement is the PAGE, and the question per page is whether it
|
|
181
|
+
* holds text SPECIFIC TO IT. Two signals, deliberately both cheap and pure:
|
|
182
|
+
*
|
|
183
|
+
* 1. **Repetition.** A line that appears on most pages, once digits are
|
|
184
|
+
* normalised away so page numbers compare equal, is a running head/footer or
|
|
185
|
+
* a scan watermark. Only short lines are eligible, so this can never strike
|
|
186
|
+
* out a paragraph of content.
|
|
187
|
+
* 2. **Volume.** What is left after (1) must reach `MIN_PAGE_TEXT_CHARS`.
|
|
188
|
+
*
|
|
189
|
+
* Boilerplate is subtracted only for this JUDGEMENT — the text handed to the
|
|
190
|
+
* model is untouched, so mis-classifying a sparse page costs a more cautious
|
|
191
|
+
* sentence rather than lost content.
|
|
192
|
+
*/
|
|
193
|
+
export interface PageTextSummary {
|
|
194
|
+
/** 1-indexed pages carrying page-specific text. */
|
|
195
|
+
textPages: number[];
|
|
196
|
+
/** 1-indexed pages carrying nothing but blanks or repeated boilerplate. */
|
|
197
|
+
imagePages: number[];
|
|
198
|
+
/** The normalised lines judged to be running heads/footers or watermarks. */
|
|
199
|
+
boilerplate: string[];
|
|
200
|
+
}
|
|
201
|
+
export declare function summarisePageText(pages: string[]): PageTextSummary;
|
|
202
|
+
/**
|
|
203
|
+
* Is this document mostly images — i.e. must it be presented as UNREAD?
|
|
204
|
+
*
|
|
205
|
+
* Takes the counts rather than the extraction so it stays pure and is the same
|
|
206
|
+
* function whether it is asked at extraction time or at prompt-building time.
|
|
207
|
+
*/
|
|
208
|
+
export declare function isMostlyImagePages(textPageCount: number, pagesScanned: number): boolean;
|
|
209
|
+
/**
|
|
210
|
+
* Everything `extractPdf` does once pdf.js has handed over the page strings.
|
|
211
|
+
*
|
|
212
|
+
* Pulled out of the browser half deliberately: pdf.js needs a DOM and this
|
|
213
|
+
* repo's vitest is `environment: 'node'`, so leaving the scanned-vs-read
|
|
214
|
+
* decision inside `extractPdf` left the most dangerous logic in the feature —
|
|
215
|
+
* "may the model treat this document as read" — with no test that could reach
|
|
216
|
+
* it. Here it is a string-array-in, extraction-out function.
|
|
217
|
+
*/
|
|
218
|
+
export interface PdfPageFit {
|
|
219
|
+
extraction: DocumentExtraction;
|
|
220
|
+
textContent?: string;
|
|
221
|
+
documentPages?: string[];
|
|
222
|
+
textTruncated?: boolean;
|
|
223
|
+
}
|
|
224
|
+
export declare function fitPdfPages(pages: string[], pageCount: number, pagesScanned: number, limit: number): PdfPageFit;
|
|
225
|
+
/** `[1,2,3,7,9,10]` → `"1-3, 7, 9-10"`. Empty in, empty out. */
|
|
226
|
+
export declare function formatPageRanges(pages: number[]): string;
|
|
227
|
+
export interface FittedPages {
|
|
228
|
+
text: string;
|
|
229
|
+
truncated: boolean;
|
|
230
|
+
/** How far into the document `text` reaches: pages 1..N were processed. */
|
|
231
|
+
pagesIncluded: number;
|
|
232
|
+
/** The 1-indexed pages whose text is actually in `text`. */
|
|
233
|
+
pageNumbers: number[];
|
|
234
|
+
/** Rendered length of every page that HAS text, before the cut. */
|
|
235
|
+
sourceChars: number;
|
|
236
|
+
/**
|
|
237
|
+
* `pages` trimmed to exactly what `text` holds, indices preserved.
|
|
238
|
+
*
|
|
239
|
+
* This is what makes the per-file cap an INVARIANT rather than a hope: the
|
|
240
|
+
* caller stores this array, so a later re-fit against the shared budget can
|
|
241
|
+
* only ever shrink it. Storing the untruncated pages instead let the shared
|
|
242
|
+
* pass re-expand a document to 20,000 characters — 2.5x the per-file cap —
|
|
243
|
+
* and starve the file attached beside it.
|
|
244
|
+
*/
|
|
245
|
+
pages: string[];
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Fit whole PDF pages into a character budget, preferring a PAGE boundary.
|
|
249
|
+
*
|
|
250
|
+
* A page is the unit a reader — and a citation — thinks in, so cutting mid-page
|
|
251
|
+
* is a worse lie than dropping the tail entirely. Falls back to a hard character
|
|
252
|
+
* cut only when the first page with text will not fit on its own, because
|
|
253
|
+
* "0 pages included" is useless to the model.
|
|
254
|
+
*
|
|
255
|
+
* Blank entries are pages the caller has judged to carry no text (see
|
|
256
|
+
* `summarisePageText`). They are skipped rather than rendered as an empty
|
|
257
|
+
* `[page N]`, which would both waste budget and read to the model as a page it
|
|
258
|
+
* had seen and found empty.
|
|
259
|
+
*/
|
|
260
|
+
export declare function truncatePagesForInline(pages: string[], limit: number): FittedPages;
|
|
261
|
+
//# sourceMappingURL=documentText.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"documentText.d.ts","sourceRoot":"","sources":["../../../src/shared/assistant/documentText.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
//#region src/shared/assistant/documentText.ts
|
|
2
|
+
var e = 2e5, t = 100, n = 24, r = .6, i = 80, a = .5, o = {
|
|
3
|
+
amp: "&",
|
|
4
|
+
lt: "<",
|
|
5
|
+
gt: ">",
|
|
6
|
+
quot: "\"",
|
|
7
|
+
apos: "'"
|
|
8
|
+
};
|
|
9
|
+
function s(e) {
|
|
10
|
+
return e.replace(/&(#x?[0-9a-fA-F]+|[a-zA-Z]+);/g, (e, t) => {
|
|
11
|
+
if (t.startsWith("#x") || t.startsWith("#X")) {
|
|
12
|
+
let n = Number.parseInt(t.slice(2), 16);
|
|
13
|
+
return Number.isFinite(n) ? String.fromCodePoint(n) : e;
|
|
14
|
+
}
|
|
15
|
+
if (t.startsWith("#")) {
|
|
16
|
+
let n = Number.parseInt(t.slice(1), 10);
|
|
17
|
+
return Number.isFinite(n) ? String.fromCodePoint(n) : e;
|
|
18
|
+
}
|
|
19
|
+
return o[t] ?? e;
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
function c(e) {
|
|
23
|
+
return e.split("\n").map((e) => e.replace(/[ \t]+$/, "")).join("\n").replace(/\n{3,}/g, "\n\n").trim();
|
|
24
|
+
}
|
|
25
|
+
function l(e) {
|
|
26
|
+
let t = e.replace(/<w:instrText[\s\S]*?<\/w:instrText>/g, ""), n = [], r = "", i = /<w:t(?:\s[^>]*)?>([\s\S]*?)<\/w:t>|<w:tab\b[^>]*\/?>|<w:br\b[^>]*\/?>|<\/w:p>/g, a;
|
|
27
|
+
for (; (a = i.exec(t)) !== null;) {
|
|
28
|
+
let [e, t] = a;
|
|
29
|
+
t === void 0 ? e.startsWith("<w:tab") ? r += " " : (e.startsWith("<w:br"), n.push(r), r = "") : r += s(t);
|
|
30
|
+
}
|
|
31
|
+
return r && n.push(r), c(n.join("\n"));
|
|
32
|
+
}
|
|
33
|
+
function u(e) {
|
|
34
|
+
return (e.match(/<si\b[^>]*\/>|<si\b[^>]*>[\s\S]*?<\/si>/g) ?? []).map((e) => (e.match(/<t(?:\s[^>]*)?>([\s\S]*?)<\/t>/g) ?? []).map((e) => s(e.replace(/<t(?:\s[^>]*)?>|<\/t>/g, ""))).join(""));
|
|
35
|
+
}
|
|
36
|
+
function d(e) {
|
|
37
|
+
let t = /^([A-Z]+)/.exec(e.toUpperCase());
|
|
38
|
+
if (!t) return -1;
|
|
39
|
+
let n = 0;
|
|
40
|
+
for (let e of t[1]) n = n * 26 + (e.charCodeAt(0) - 64);
|
|
41
|
+
return n - 1;
|
|
42
|
+
}
|
|
43
|
+
function f(e) {
|
|
44
|
+
return /[",\n]/.test(e) ? `"${e.replace(/"/g, "\"\"")}"` : e;
|
|
45
|
+
}
|
|
46
|
+
function p(e, t) {
|
|
47
|
+
let n = [], r = /<row\b[^>]*\/>|<row\b[^>]*>([\s\S]*?)<\/row>/g, i;
|
|
48
|
+
for (; (i = r.exec(e)) !== null;) {
|
|
49
|
+
let e = i[1] ?? "", r = [], a = /<c\b([^>]*?)(?:\/>|>([\s\S]*?)<\/c>)/g, o;
|
|
50
|
+
for (; (o = a.exec(e)) !== null;) {
|
|
51
|
+
let e = o[1] ?? "", n = o[2] ?? "", i = /\bt="([^"]+)"/.exec(e)?.[1] ?? "n", a = /\br="([^"]+)"/.exec(e)?.[1] ?? "", c;
|
|
52
|
+
if (i === "s") {
|
|
53
|
+
let e = /<v(?:\s[^>]*)?>([\s\S]*?)<\/v>/.exec(n)?.[1] ?? "";
|
|
54
|
+
c = t[Number.parseInt(e, 10)] ?? "";
|
|
55
|
+
} else if (i === "inlineStr") c = (n.match(/<t(?:\s[^>]*)?>([\s\S]*?)<\/t>/g) ?? []).map((e) => s(e.replace(/<t(?:\s[^>]*)?>|<\/t>/g, ""))).join("");
|
|
56
|
+
else {
|
|
57
|
+
let e = /<v(?:\s[^>]*)?>([\s\S]*?)<\/v>/.exec(n)?.[1] ?? "";
|
|
58
|
+
c = i === "b" ? e === "1" ? "TRUE" : e === "0" ? "FALSE" : "" : s(e);
|
|
59
|
+
}
|
|
60
|
+
let l = d(a);
|
|
61
|
+
if (l >= 0) {
|
|
62
|
+
for (; r.length < l;) r.push("");
|
|
63
|
+
r[l] = c;
|
|
64
|
+
} else r.push(c);
|
|
65
|
+
}
|
|
66
|
+
for (; r.length > 0 && r[r.length - 1] === "";) r.pop();
|
|
67
|
+
n.push(r.map(f).join(","));
|
|
68
|
+
}
|
|
69
|
+
for (; n.length > 0 && n[n.length - 1] === "";) n.pop();
|
|
70
|
+
return n;
|
|
71
|
+
}
|
|
72
|
+
function m(e, t) {
|
|
73
|
+
let n = /* @__PURE__ */ new Map();
|
|
74
|
+
for (let e of t.match(/<Relationship\b[^>]*\/?>/g) ?? []) {
|
|
75
|
+
let t = /\bId="([^"]+)"/.exec(e)?.[1], r = /\bTarget="([^"]+)"/.exec(e)?.[1];
|
|
76
|
+
if (!t || !r) continue;
|
|
77
|
+
let i = r.replace(/^\/xl\//, "").replace(/^\.\//, "");
|
|
78
|
+
n.set(t, i.startsWith("xl/") ? i : `xl/${i}`);
|
|
79
|
+
}
|
|
80
|
+
return (e.match(/<sheet\b[^>]*\/?>/g) ?? []).map((e) => {
|
|
81
|
+
let t = s(/\bname="([^"]*)"/.exec(e)?.[1] ?? "Sheet"), r = /\br:id="([^"]+)"/.exec(e)?.[1] ?? "";
|
|
82
|
+
return {
|
|
83
|
+
name: t,
|
|
84
|
+
path: n.get(r) ?? null
|
|
85
|
+
};
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
function h(e) {
|
|
89
|
+
return c(e.filter((e) => e.rows.length > 0).map((e) => `## Sheet: ${e.name}\n${e.rows.join("\n")}`).join("\n\n"));
|
|
90
|
+
}
|
|
91
|
+
function g(e) {
|
|
92
|
+
let t = "";
|
|
93
|
+
for (let n of e) typeof n.str == "string" && (t += n.str, n.hasEOL && (t += "\n"));
|
|
94
|
+
return c(t);
|
|
95
|
+
}
|
|
96
|
+
function _(e) {
|
|
97
|
+
return `[page ${e}]`;
|
|
98
|
+
}
|
|
99
|
+
var v = /^\s*(?:page|p\.?|pg\.?)?\s*\d+(?:\s*(?:of|\/)\s*\d+)?\s*(?:[-–—|]\s*)?/i, y = /\s*(?:[-–—|]\s*)?(?:page|p\.?|pg\.?)?\s*\d+(?:\s*(?:of|\/)\s*\d+)?\s*$/i;
|
|
100
|
+
function b(e) {
|
|
101
|
+
let t = e.replace(/\s+/g, " ").trim().toLowerCase();
|
|
102
|
+
return (t.replace(v, "") || t).replace(y, "").trim();
|
|
103
|
+
}
|
|
104
|
+
function x(e) {
|
|
105
|
+
let t = e.map((e) => {
|
|
106
|
+
let t = /* @__PURE__ */ new Set();
|
|
107
|
+
for (let n of e.split("\n")) {
|
|
108
|
+
let e = b(n);
|
|
109
|
+
e !== "" && t.add(e);
|
|
110
|
+
}
|
|
111
|
+
return t;
|
|
112
|
+
}), n = /* @__PURE__ */ new Map();
|
|
113
|
+
for (let e of t) for (let t of e) n.set(t, (n.get(t) ?? 0) + 1);
|
|
114
|
+
let i = Math.max(2, Math.ceil(e.length * r)), a = /* @__PURE__ */ new Set();
|
|
115
|
+
for (let [e, t] of n) t >= i && e.length <= 80 && a.add(e);
|
|
116
|
+
let o = [], s = [];
|
|
117
|
+
return e.forEach((e, t) => {
|
|
118
|
+
(e.split("\n").filter((e) => {
|
|
119
|
+
let t = b(e);
|
|
120
|
+
return t !== "" && !a.has(t);
|
|
121
|
+
}).join("\n").trim().length >= 24 ? o : s).push(t + 1);
|
|
122
|
+
}), {
|
|
123
|
+
textPages: o,
|
|
124
|
+
imagePages: s,
|
|
125
|
+
boilerplate: [...a]
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function S(e, t) {
|
|
129
|
+
return t <= 0 ? !1 : e < t * a;
|
|
130
|
+
}
|
|
131
|
+
function C(e, t, n, r) {
|
|
132
|
+
let i = x(e);
|
|
133
|
+
if (i.textPages.length === 0) return { extraction: {
|
|
134
|
+
status: "no-text",
|
|
135
|
+
pageCount: t,
|
|
136
|
+
pagesScanned: n
|
|
137
|
+
} };
|
|
138
|
+
let a = new Set(i.textPages), o = T(e.map((e, t) => a.has(t + 1) ? e : ""), r);
|
|
139
|
+
return o.text === "" ? { extraction: {
|
|
140
|
+
status: "no-text",
|
|
141
|
+
pageCount: t,
|
|
142
|
+
pagesScanned: n
|
|
143
|
+
} } : {
|
|
144
|
+
extraction: {
|
|
145
|
+
status: "ok",
|
|
146
|
+
pageCount: t,
|
|
147
|
+
pagesScanned: n,
|
|
148
|
+
pagesIncluded: o.pagesIncluded,
|
|
149
|
+
pageNumbers: o.pageNumbers,
|
|
150
|
+
imagePages: i.imagePages,
|
|
151
|
+
textPageCount: i.textPages.length,
|
|
152
|
+
sourceChars: o.sourceChars
|
|
153
|
+
},
|
|
154
|
+
textContent: o.text,
|
|
155
|
+
documentPages: o.pages,
|
|
156
|
+
textTruncated: o.truncated || n < t
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
function w(e) {
|
|
160
|
+
let t = [...new Set(e)].sort((e, t) => e - t), n = [], r = null, i = 0, a = () => {
|
|
161
|
+
r !== null && n.push(r === i ? `${r}` : `${r}-${i}`);
|
|
162
|
+
};
|
|
163
|
+
for (let e of t) {
|
|
164
|
+
if (r === null) {
|
|
165
|
+
r = i = e;
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
if (e === i + 1) {
|
|
169
|
+
i = e;
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
a(), r = i = e;
|
|
173
|
+
}
|
|
174
|
+
return a(), n.join(", ");
|
|
175
|
+
}
|
|
176
|
+
function T(e, t) {
|
|
177
|
+
let n = (e, t) => `${_(t + 1)}\n${e}`, r = e.map((e, t) => ({
|
|
178
|
+
index: t,
|
|
179
|
+
page: e,
|
|
180
|
+
rendered: n(e, t)
|
|
181
|
+
})).filter((e) => e.page.trim() !== ""), i = r.map((e) => e.rendered).join("\n\n").length;
|
|
182
|
+
if (r.length === 0) return {
|
|
183
|
+
text: "",
|
|
184
|
+
truncated: !1,
|
|
185
|
+
pagesIncluded: e.length,
|
|
186
|
+
pageNumbers: [],
|
|
187
|
+
sourceChars: 0,
|
|
188
|
+
pages: []
|
|
189
|
+
};
|
|
190
|
+
let a = [], o = 0, s = 0, c = !1;
|
|
191
|
+
for (let r = 0; r < e.length; r += 1) {
|
|
192
|
+
if (e[r].trim() === "") {
|
|
193
|
+
s = r + 1;
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
let i = n(e[r], r), l = a.length === 0 ? i.length : i.length + 2;
|
|
197
|
+
if (o + l > t) {
|
|
198
|
+
c = !0;
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
a.push({
|
|
202
|
+
index: r,
|
|
203
|
+
page: e[r],
|
|
204
|
+
rendered: i
|
|
205
|
+
}), o += l, s = r + 1;
|
|
206
|
+
}
|
|
207
|
+
if (a.length > 0) return {
|
|
208
|
+
text: a.map((e) => e.rendered).join("\n\n"),
|
|
209
|
+
truncated: c,
|
|
210
|
+
pagesIncluded: s,
|
|
211
|
+
pageNumbers: a.map((e) => e.index + 1),
|
|
212
|
+
sourceChars: i,
|
|
213
|
+
pages: e.slice(0, s)
|
|
214
|
+
};
|
|
215
|
+
let l = r[0], u = l.rendered.slice(0, Math.max(0, t)), d = u.lastIndexOf("\n"), f = d > t * .5 ? u.slice(0, d) : u, p = f.slice(_(l.index + 1).length + 1);
|
|
216
|
+
if (p.trim() === "") return {
|
|
217
|
+
text: "",
|
|
218
|
+
truncated: !0,
|
|
219
|
+
pagesIncluded: 0,
|
|
220
|
+
pageNumbers: [],
|
|
221
|
+
sourceChars: i,
|
|
222
|
+
pages: []
|
|
223
|
+
};
|
|
224
|
+
let m = e.slice(0, l.index + 1);
|
|
225
|
+
return m[l.index] = p, {
|
|
226
|
+
text: f,
|
|
227
|
+
truncated: !0,
|
|
228
|
+
pagesIncluded: l.index + 1,
|
|
229
|
+
pageNumbers: [l.index + 1],
|
|
230
|
+
sourceChars: i,
|
|
231
|
+
pages: m
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
//#endregion
|
|
235
|
+
export { r as BOILERPLATE_PAGE_SHARE, i as MAX_BOILERPLATE_LINE_CHARS, e as MAX_EXTRACTED_CHARS, t as MAX_PDF_PAGES_SCANNED, n as MIN_PAGE_TEXT_CHARS, a as MIN_TEXT_PAGE_SHARE, d as columnLetterToIndex, s as decodeXmlEntities, l as docxXmlToText, C as fitPdfPages, w as formatPageRanges, S as isMostlyImagePages, h as joinSheets, _ as pageMarker, u as parseSharedStrings, m as parseWorkbookSheets, g as pdfTextItemsToPage, p as sheetXmlToRows, x as summarisePageText, T as truncatePagesForInline };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hard limits imposed by the gateways this app talks to.
|
|
3
|
+
*
|
|
4
|
+
* These are not our numbers — they are deployment facts, and getting them wrong
|
|
5
|
+
* is expensive because the failure is opaque. `wspace-public-gateway` sets
|
|
6
|
+
* `MAX_REQUEST_BODY_SIZE: 256kb` in BOTH environments (burdenoff-gitops,
|
|
7
|
+
* `apps/config-workspace/wspace-public-gateway-config.yaml:21` and
|
|
8
|
+
* `apps/config-workspace-prod/…:21`). It compares Content-Length and answers
|
|
9
|
+
* 413 *before* authenticating and before forwarding, and fe-libs' `graphqlFetch`
|
|
10
|
+
* discards the status — so the user is told "The request could not be processed.
|
|
11
|
+
* Please refresh and try again." with nothing in it to suggest the payload was
|
|
12
|
+
* simply too big.
|
|
13
|
+
*
|
|
14
|
+
* Anything that POSTs base64 from the browser has to be sized against this.
|
|
15
|
+
*/
|
|
16
|
+
export declare const MAX_REQUEST_BODY_BYTES = 262144;
|
|
17
|
+
/**
|
|
18
|
+
* What is left for a base64 image once the rest of a GraphQL request is paid
|
|
19
|
+
* for: the query document, operation name, variables, and the workspace/org
|
|
20
|
+
* context envelope. 32 KB is deliberately generous — the point is to fail in
|
|
21
|
+
* OUR code with a sentence the user can act on, rather than at the gateway with
|
|
22
|
+
* one they cannot.
|
|
23
|
+
*/
|
|
24
|
+
export declare const MAX_INLINE_IMAGE_BASE64_BYTES: number;
|
|
25
|
+
//# sourceMappingURL=gatewayLimits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gatewayLimits.d.ts","sourceRoot":"","sources":["../../../src/shared/assistant/gatewayLimits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,sBAAsB,SAAU,CAAC;AAE9C;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,QAAkC,CAAC"}
|
|
@@ -63,4 +63,10 @@ export * from './i18n';
|
|
|
63
63
|
export * from './voice/speechLabels';
|
|
64
64
|
export * from './voice/replyLanguage';
|
|
65
65
|
export * from './voice/speechPlayback';
|
|
66
|
+
export * from './conversation';
|
|
67
|
+
export * from './attachments';
|
|
68
|
+
export * from './store';
|
|
69
|
+
export * from './turnState';
|
|
70
|
+
export * from './gatewayLimits';
|
|
71
|
+
export * from './documentText';
|
|
66
72
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shared/assistant/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAGH,cAAc,gCAAgC,CAAC;AAC/C,cAAc,mCAAmC,CAAC;AAClD,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,OAAO,CAAC;AACtB,cAAc,SAAS,CAAC;AAGxB,cAAc,wBAAwB,CAAC;AAKvC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,+BAA+B,CAAC;AAG9C,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAGlC,cAAc,gBAAgB,CAAC;AAK/B,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,4BAA4B,CAAC;AAG3C,cAAc,QAAQ,CAAC;AAEvB,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shared/assistant/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAGH,cAAc,gCAAgC,CAAC;AAC/C,cAAc,mCAAmC,CAAC;AAClD,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,OAAO,CAAC;AACtB,cAAc,SAAS,CAAC;AAGxB,cAAc,wBAAwB,CAAC;AAKvC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,+BAA+B,CAAC;AAG9C,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAGlC,cAAc,gBAAgB,CAAC;AAK/B,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,4BAA4B,CAAC;AAG3C,cAAc,QAAQ,CAAC;AAEvB,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AAGvC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { AssistantConversationProcessing, AssistantConversationStatus, AssistantMessageMetadata, AssistantSandboxRuntime, AssistantSandboxStatus, Conversation, Message } from './conversation';
|
|
2
|
+
import { AssistantMode } from './types';
|
|
3
|
+
interface AssistantState {
|
|
4
|
+
conversations: Conversation[];
|
|
5
|
+
activeConversationId: string | null;
|
|
6
|
+
mode: AssistantMode;
|
|
7
|
+
processingByConversationId: Record<string, AssistantConversationProcessing>;
|
|
8
|
+
conversationListOpen: boolean;
|
|
9
|
+
/** Active sandboxes keyed by assistant mode */
|
|
10
|
+
sandboxesByMode: Partial<Record<AssistantMode, AssistantSandboxRuntime>>;
|
|
11
|
+
/**
|
|
12
|
+
* A prompt queued up for auto-submit by the chat area. Used by the
|
|
13
|
+
* `GetHelpButton` / `useOpenAssistantHelp` hook so pages can prompt the
|
|
14
|
+
* assistant contextually from an empty state button without coupling to
|
|
15
|
+
* the chat area internals.
|
|
16
|
+
*/
|
|
17
|
+
pendingPrompt: string | null;
|
|
18
|
+
/**
|
|
19
|
+
* Whether the user has acknowledged the api-calls (write) mode consent
|
|
20
|
+
* dialog. Persisted per-profile so the warning shows once, not every switch.
|
|
21
|
+
*/
|
|
22
|
+
apiCallsAcknowledged: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Read every assistant reply aloud as it settles (BOFF-6290).
|
|
25
|
+
*
|
|
26
|
+
* Persisted per-profile and **false by default**: speech is opt-in, and the
|
|
27
|
+
* assistant must never start talking without an explicit prior choice. A
|
|
28
|
+
* one-off "read this message" needs no preference at all — it is the speak
|
|
29
|
+
* button on the message.
|
|
30
|
+
*/
|
|
31
|
+
autoSpeakEnabled: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* The language the user speaks TO the assistant, independent of the interface
|
|
34
|
+
* language (BOFF-7108). `null` means "follow the app locale", which is what
|
|
35
|
+
* every user gets until they choose otherwise — and is exactly the behaviour
|
|
36
|
+
* that existed before this preference did.
|
|
37
|
+
*/
|
|
38
|
+
assistantLanguage: string | null;
|
|
39
|
+
/**
|
|
40
|
+
* The language the assistant ANSWERS in. `null` means "match my language" —
|
|
41
|
+
* i.e. follow `assistantLanguage` — which is the default and what shipped
|
|
42
|
+
* before the two were separated.
|
|
43
|
+
*/
|
|
44
|
+
replyLanguage: string | null;
|
|
45
|
+
/**
|
|
46
|
+
* The voice the user picked, keyed by language code (BOFF-7110).
|
|
47
|
+
*
|
|
48
|
+
* Per language, because a voice only reads one: picking "Google US English"
|
|
49
|
+
* says nothing about which Tamil voice to use. Stored by NAME because that is
|
|
50
|
+
* the only identifier stable across page loads — voice objects are recreated
|
|
51
|
+
* each time and `voiceURI` is not reliably unique across platforms.
|
|
52
|
+
*
|
|
53
|
+
* A name saved on one device will not resolve on another; that is handled by
|
|
54
|
+
* falling back to the ranking rather than by trying to sync it.
|
|
55
|
+
*/
|
|
56
|
+
preferredVoices: Record<string, string>;
|
|
57
|
+
createConversation: (title?: string, mode?: AssistantMode) => string;
|
|
58
|
+
deleteConversation: (id: string) => void;
|
|
59
|
+
renameConversation: (id: string, title: string) => void;
|
|
60
|
+
setActiveConversation: (id: string | null) => void;
|
|
61
|
+
setMode: (mode: AssistantMode) => void;
|
|
62
|
+
setConversationMode: (conversationId: string, mode: AssistantMode) => void;
|
|
63
|
+
addMessage: (conversationId: string, message: Message) => void;
|
|
64
|
+
updateMessage: (conversationId: string, messageId: string, content: string) => void;
|
|
65
|
+
patchMessage: (conversationId: string, messageId: string, patch: Partial<Message>) => void;
|
|
66
|
+
/**
|
|
67
|
+
* MERGE into a message's metadata, leaving untouched keys alone.
|
|
68
|
+
*
|
|
69
|
+
* ★ The counterpart to `patchMessage`, which REPLACES `metadata` wholesale
|
|
70
|
+
* (`{...m, ...patch}`). That has already shipped one defect: a write which
|
|
71
|
+
* rebuilt the object dropped `voice`, so a spoken reply silently became a
|
|
72
|
+
* typed one. Anything adding a SINGLE metadata key should use this, or it
|
|
73
|
+
* takes `lang` and `voice` down with it.
|
|
74
|
+
*/
|
|
75
|
+
mergeMessageMetadata: (conversationId: string, messageId: string, patch: Partial<AssistantMessageMetadata>) => void;
|
|
76
|
+
setConversationProcessing: (conversationId: string, status: AssistantConversationStatus, messageId?: string | null, error?: string | null) => void;
|
|
77
|
+
clearConversationProcessing: (conversationId: string) => void;
|
|
78
|
+
toggleConversationList: () => void;
|
|
79
|
+
setConversationListOpen: (open: boolean) => void;
|
|
80
|
+
clearConversation: (id: string) => void;
|
|
81
|
+
setBackendSessionId: (conversationId: string, sessionId: string) => void;
|
|
82
|
+
clearBackendSessionId: (conversationId: string) => void;
|
|
83
|
+
setSandbox: (mode: AssistantMode, sandboxId: string | null, status: AssistantSandboxStatus) => void;
|
|
84
|
+
clearSandbox: (mode: AssistantMode) => void;
|
|
85
|
+
resetStore: () => void;
|
|
86
|
+
/** Queue a prompt for the chat area to auto-send on next render. */
|
|
87
|
+
submitPrompt: (text: string) => void;
|
|
88
|
+
/** Returns and clears any queued prompt. */
|
|
89
|
+
consumePendingPrompt: () => string | null;
|
|
90
|
+
/** Mark the api-calls write-mode consent as acknowledged (persisted). */
|
|
91
|
+
acknowledgeApiCalls: () => void;
|
|
92
|
+
/** Turn automatic read-aloud of new replies on or off (persisted). */
|
|
93
|
+
setAutoSpeak: (enabled: boolean) => void;
|
|
94
|
+
/** Choose the language spoken to the assistant; `null` follows the app locale (persisted). */
|
|
95
|
+
setAssistantLanguage: (code: string | null) => void;
|
|
96
|
+
setReplyLanguage: (code: string | null) => void;
|
|
97
|
+
/** `null` clears the pick for that language, restoring the ranked default. */
|
|
98
|
+
setPreferredVoice: (languageCode: string, voiceName: string | null) => void;
|
|
99
|
+
}
|
|
100
|
+
export declare const useAssistantStore: import('zustand').UseBoundStore<Omit<import('zustand').StoreApi<AssistantState>, "setState" | "persist"> & {
|
|
101
|
+
setState(partial: AssistantState | Partial<AssistantState> | ((state: AssistantState) => AssistantState | Partial<AssistantState>), replace?: false | undefined): unknown;
|
|
102
|
+
setState(state: AssistantState | ((state: AssistantState) => AssistantState), replace: true): unknown;
|
|
103
|
+
persist: {
|
|
104
|
+
setOptions: (options: Partial<import('zustand/middleware').PersistOptions<AssistantState, unknown, unknown>>) => void;
|
|
105
|
+
clearStorage: () => void;
|
|
106
|
+
rehydrate: () => Promise<void> | void;
|
|
107
|
+
hasHydrated: () => boolean;
|
|
108
|
+
onHydrate: (fn: (state: AssistantState) => void) => () => void;
|
|
109
|
+
onFinishHydration: (fn: (state: AssistantState) => void) => () => void;
|
|
110
|
+
getOptions: () => Partial<import('zustand/middleware').PersistOptions<AssistantState, unknown, unknown>>;
|
|
111
|
+
};
|
|
112
|
+
}>;
|
|
113
|
+
export {};
|
|
114
|
+
//# sourceMappingURL=store.d.ts.map
|