agentxl 1.0.0 → 1.1.2
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/LICENSE +21 -0
- package/README.md +352 -197
- package/bin/agentxl-folder-picker.exe +0 -0
- package/bin/agentxl.js +44 -8
- package/dist/agent/models.d.ts +9 -9
- package/dist/agent/models.d.ts.map +1 -1
- package/dist/agent/models.js +44 -8
- package/dist/agent/models.js.map +1 -1
- package/dist/agent/prompt/folder-context.d.ts +26 -0
- package/dist/agent/prompt/folder-context.d.ts.map +1 -0
- package/dist/agent/prompt/folder-context.js +105 -0
- package/dist/agent/prompt/folder-context.js.map +1 -0
- package/dist/agent/prompt/system-prompt.d.ts +21 -0
- package/dist/agent/prompt/system-prompt.d.ts.map +1 -0
- package/dist/agent/prompt/system-prompt.js +130 -0
- package/dist/agent/prompt/system-prompt.js.map +1 -0
- package/dist/agent/session.d.ts +10 -4
- package/dist/agent/session.d.ts.map +1 -1
- package/dist/agent/session.js +53 -15
- package/dist/agent/session.js.map +1 -1
- package/dist/agent/tools/excel.d.ts +24 -0
- package/dist/agent/tools/excel.d.ts.map +1 -0
- package/dist/agent/tools/excel.js +132 -0
- package/dist/agent/tools/excel.js.map +1 -0
- package/dist/server/document-converter.d.ts +71 -0
- package/dist/server/document-converter.d.ts.map +1 -0
- package/dist/server/document-converter.js +353 -0
- package/dist/server/document-converter.js.map +1 -0
- package/dist/server/excel-bridge.d.ts +38 -0
- package/dist/server/excel-bridge.d.ts.map +1 -0
- package/dist/server/excel-bridge.js +75 -0
- package/dist/server/excel-bridge.js.map +1 -0
- package/dist/server/folder-picker.d.ts +9 -0
- package/dist/server/folder-picker.d.ts.map +1 -0
- package/dist/server/folder-picker.js +204 -0
- package/dist/server/folder-picker.js.map +1 -0
- package/dist/server/folder-scanner.d.ts +43 -0
- package/dist/server/folder-scanner.d.ts.map +1 -0
- package/dist/server/folder-scanner.js +161 -0
- package/dist/server/folder-scanner.js.map +1 -0
- package/dist/server/http.d.ts +19 -0
- package/dist/server/http.d.ts.map +1 -0
- package/dist/server/http.js +62 -0
- package/dist/server/http.js.map +1 -0
- package/dist/server/index.d.ts +16 -4
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +70 -246
- package/dist/server/index.js.map +1 -1
- package/dist/server/json-store.d.ts +19 -0
- package/dist/server/json-store.d.ts.map +1 -0
- package/dist/server/json-store.js +37 -0
- package/dist/server/json-store.js.map +1 -0
- package/dist/server/routes/agent.d.ts +16 -0
- package/dist/server/routes/agent.d.ts.map +1 -0
- package/dist/server/routes/agent.js +196 -0
- package/dist/server/routes/agent.js.map +1 -0
- package/dist/server/routes/excel.d.ts +10 -0
- package/dist/server/routes/excel.d.ts.map +1 -0
- package/dist/server/routes/excel.js +41 -0
- package/dist/server/routes/excel.js.map +1 -0
- package/dist/server/routes/folder.d.ts +15 -0
- package/dist/server/routes/folder.d.ts.map +1 -0
- package/dist/server/routes/folder.js +184 -0
- package/dist/server/routes/folder.js.map +1 -0
- package/dist/server/routes/workbook.d.ts +7 -0
- package/dist/server/routes/workbook.d.ts.map +1 -0
- package/dist/server/routes/workbook.js +31 -0
- package/dist/server/routes/workbook.js.map +1 -0
- package/dist/server/static.d.ts +12 -0
- package/dist/server/static.d.ts.map +1 -0
- package/dist/server/static.js +83 -0
- package/dist/server/static.js.map +1 -0
- package/dist/server/workbook-folder-store.d.ts +24 -0
- package/dist/server/workbook-folder-store.d.ts.map +1 -0
- package/dist/server/workbook-folder-store.js +76 -0
- package/dist/server/workbook-folder-store.js.map +1 -0
- package/dist/server/workbook-identity.d.ts +8 -0
- package/dist/server/workbook-identity.d.ts.map +1 -0
- package/dist/server/workbook-identity.js +57 -0
- package/dist/server/workbook-identity.js.map +1 -0
- package/manifest/manifest-hosted.xml +107 -0
- package/package.json +24 -10
- package/taskpane/dist/assets/index-BnD8psE_.js +224 -0
- package/taskpane/dist/assets/index-BuAcDfRq.css +1 -0
- package/taskpane/dist/index.html +2 -2
- package/taskpane/dist/assets/index-6sMpIYxE.css +0 -1
- package/taskpane/dist/assets/index-DyLrQ3Aa.js +0 -164
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Document pre-converter — converts binary documents to readable Markdown.
|
|
3
|
+
*
|
|
4
|
+
* Runs at scan time (or on demand). Cached converted files live alongside
|
|
5
|
+
* the source files in a `.agentxl-cache/` directory inside the linked folder.
|
|
6
|
+
*
|
|
7
|
+
* PDF conversion strategy:
|
|
8
|
+
* 1. Try pdf-parse (fast, local, free) — extracts embedded text
|
|
9
|
+
* 2. Check if extracted text is meaningful (chars-per-page heuristic)
|
|
10
|
+
* 3. If scanned/image PDF → fall back to Mistral OCR API
|
|
11
|
+
*
|
|
12
|
+
* XLSX and DOCX are NOT pre-converted — the agent writes extraction code
|
|
13
|
+
* at runtime via bash, which is more powerful for structured data.
|
|
14
|
+
*/
|
|
15
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, statSync } from "fs";
|
|
16
|
+
import { join, dirname, basename, relative } from "path";
|
|
17
|
+
/** Name of the cache directory inside the linked folder. */
|
|
18
|
+
const CACHE_DIR = ".agentxl-cache";
|
|
19
|
+
/**
|
|
20
|
+
* Minimum average characters per page to consider text extraction successful.
|
|
21
|
+
* Below this threshold, the PDF is likely scanned/image-based and needs OCR.
|
|
22
|
+
*/
|
|
23
|
+
const MIN_CHARS_PER_PAGE = 50;
|
|
24
|
+
/**
|
|
25
|
+
* Extract text from a PDF using pdf-parse (local, no API call).
|
|
26
|
+
* Returns null if the PDF has no meaningful embedded text.
|
|
27
|
+
*/
|
|
28
|
+
async function extractPdfText(pdfPath) {
|
|
29
|
+
try {
|
|
30
|
+
const { PDFParse } = await import("pdf-parse");
|
|
31
|
+
const buffer = readFileSync(pdfPath);
|
|
32
|
+
const parser = new PDFParse({ data: new Uint8Array(buffer) });
|
|
33
|
+
const result = await parser.getText();
|
|
34
|
+
let title;
|
|
35
|
+
let author;
|
|
36
|
+
try {
|
|
37
|
+
const infoResult = await parser.getInfo();
|
|
38
|
+
const meta = infoResult?.info;
|
|
39
|
+
if (meta?.Title && typeof meta.Title === "string")
|
|
40
|
+
title = meta.Title;
|
|
41
|
+
if (meta?.Author && typeof meta.Author === "string")
|
|
42
|
+
author = meta.Author;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// Metadata is optional
|
|
46
|
+
}
|
|
47
|
+
await parser.destroy();
|
|
48
|
+
const cleanText = result.text.trim();
|
|
49
|
+
return {
|
|
50
|
+
text: cleanText,
|
|
51
|
+
pageCount: result.total,
|
|
52
|
+
title,
|
|
53
|
+
author,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Check if extracted text is meaningful (not just whitespace/control chars).
|
|
62
|
+
* Scanned PDFs often return empty or near-empty text.
|
|
63
|
+
*/
|
|
64
|
+
function isTextMeaningful(text, pageCount) {
|
|
65
|
+
if (!text || pageCount === 0)
|
|
66
|
+
return false;
|
|
67
|
+
// Strip whitespace and control characters
|
|
68
|
+
const meaningful = text.replace(/[\s\x00-\x1f]/g, "");
|
|
69
|
+
const charsPerPage = meaningful.length / pageCount;
|
|
70
|
+
return charsPerPage >= MIN_CHARS_PER_PAGE;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Detect which OCR provider is available.
|
|
74
|
+
* Priority: Azure Mistral (enterprise) → direct Mistral → null
|
|
75
|
+
*/
|
|
76
|
+
function getOcrConfig() {
|
|
77
|
+
// Azure Mistral (enterprise — Azure AI Services)
|
|
78
|
+
const azureEndpoint = process.env.AZURE_MISTRAL_ENDPOINT?.trim();
|
|
79
|
+
const azureKey = process.env.AZURE_MISTRAL_API_KEY?.trim();
|
|
80
|
+
if (azureEndpoint && azureKey) {
|
|
81
|
+
return { provider: "azure-mistral", endpoint: azureEndpoint, apiKey: azureKey };
|
|
82
|
+
}
|
|
83
|
+
// Direct Mistral API
|
|
84
|
+
const mistralKey = process.env.MISTRAL_API_KEY?.trim();
|
|
85
|
+
if (mistralKey) {
|
|
86
|
+
return { provider: "mistral", apiKey: mistralKey };
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
// Azure Mistral OCR
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
/**
|
|
94
|
+
* OCR a PDF using Azure-hosted Mistral OCR.
|
|
95
|
+
* Sends the PDF as a base64 data URL — no file upload step needed.
|
|
96
|
+
*/
|
|
97
|
+
async function ocrWithAzureMistral(pdfPath, endpoint, apiKey) {
|
|
98
|
+
const buffer = readFileSync(pdfPath);
|
|
99
|
+
const base64 = buffer.toString("base64");
|
|
100
|
+
const dataUrl = `data:application/pdf;base64,${base64}`;
|
|
101
|
+
const response = await fetch(endpoint, {
|
|
102
|
+
method: "POST",
|
|
103
|
+
headers: {
|
|
104
|
+
"Content-Type": "application/json",
|
|
105
|
+
"api-key": apiKey,
|
|
106
|
+
},
|
|
107
|
+
body: JSON.stringify({
|
|
108
|
+
model: "mistral-ocr-latest",
|
|
109
|
+
document: {
|
|
110
|
+
type: "document_url",
|
|
111
|
+
document_url: dataUrl,
|
|
112
|
+
},
|
|
113
|
+
table_format: "markdown",
|
|
114
|
+
}),
|
|
115
|
+
});
|
|
116
|
+
if (!response.ok) {
|
|
117
|
+
const body = await response.text().catch(() => "");
|
|
118
|
+
throw new Error(`Azure Mistral OCR failed (${response.status}): ${body.slice(0, 200)}`);
|
|
119
|
+
}
|
|
120
|
+
const result = (await response.json());
|
|
121
|
+
return result.pages.map((p) => p.markdown).join("\n\n---\n\n");
|
|
122
|
+
}
|
|
123
|
+
// ---------------------------------------------------------------------------
|
|
124
|
+
// Direct Mistral OCR
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
/**
|
|
127
|
+
* OCR a PDF using Mistral's direct API.
|
|
128
|
+
* Uploads the file, runs OCR, returns markdown.
|
|
129
|
+
*/
|
|
130
|
+
async function ocrWithDirectMistral(pdfPath, apiKey) {
|
|
131
|
+
const { Mistral } = await import("@mistralai/mistralai");
|
|
132
|
+
const client = new Mistral({ apiKey });
|
|
133
|
+
// Upload the PDF file
|
|
134
|
+
const buffer = readFileSync(pdfPath);
|
|
135
|
+
const fileName = basename(pdfPath);
|
|
136
|
+
const blob = new Blob([buffer], { type: "application/pdf" });
|
|
137
|
+
const file = new File([blob], fileName, { type: "application/pdf" });
|
|
138
|
+
const uploaded = await client.files.upload({
|
|
139
|
+
file,
|
|
140
|
+
purpose: "ocr",
|
|
141
|
+
});
|
|
142
|
+
// Run OCR
|
|
143
|
+
const ocrResult = await client.ocr.process({
|
|
144
|
+
model: "mistral-ocr-latest",
|
|
145
|
+
document: {
|
|
146
|
+
type: "file",
|
|
147
|
+
fileId: uploaded.id,
|
|
148
|
+
},
|
|
149
|
+
tableFormat: "markdown",
|
|
150
|
+
});
|
|
151
|
+
// Combine all pages into markdown
|
|
152
|
+
const pages = ocrResult.pages.map((page) => page.markdown);
|
|
153
|
+
// Clean up the uploaded file (best effort)
|
|
154
|
+
try {
|
|
155
|
+
await client.files.delete({ fileId: uploaded.id });
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
// Non-fatal
|
|
159
|
+
}
|
|
160
|
+
return pages.join("\n\n---\n\n");
|
|
161
|
+
}
|
|
162
|
+
// ---------------------------------------------------------------------------
|
|
163
|
+
// Unified OCR dispatcher
|
|
164
|
+
// ---------------------------------------------------------------------------
|
|
165
|
+
/**
|
|
166
|
+
* OCR a PDF using the best available provider.
|
|
167
|
+
*/
|
|
168
|
+
async function ocrPdf(pdfPath) {
|
|
169
|
+
const config = getOcrConfig();
|
|
170
|
+
if (!config) {
|
|
171
|
+
throw new Error("No OCR provider configured. Scanned PDFs need Mistral OCR.\n" +
|
|
172
|
+
"Set AZURE_MISTRAL_ENDPOINT + AZURE_MISTRAL_API_KEY (Azure)\n" +
|
|
173
|
+
"or MISTRAL_API_KEY (direct) in .env to enable OCR.");
|
|
174
|
+
}
|
|
175
|
+
if (config.provider === "azure-mistral") {
|
|
176
|
+
return ocrWithAzureMistral(pdfPath, config.endpoint, config.apiKey);
|
|
177
|
+
}
|
|
178
|
+
return ocrWithDirectMistral(pdfPath, config.apiKey);
|
|
179
|
+
}
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
// PDF → Markdown (smart: text-first, OCR fallback)
|
|
182
|
+
// ---------------------------------------------------------------------------
|
|
183
|
+
/**
|
|
184
|
+
* Convert a single PDF to Markdown.
|
|
185
|
+
*
|
|
186
|
+
* Strategy:
|
|
187
|
+
* 1. Try local text extraction (pdf-parse) — fast, free
|
|
188
|
+
* 2. If text is empty/sparse → PDF is scanned → use Mistral OCR
|
|
189
|
+
* 3. If no Mistral key → return what we have with a warning
|
|
190
|
+
*/
|
|
191
|
+
async function pdfToMarkdown(pdfPath) {
|
|
192
|
+
const fileName = basename(pdfPath);
|
|
193
|
+
// Step 1: Try local text extraction
|
|
194
|
+
const extraction = await extractPdfText(pdfPath);
|
|
195
|
+
if (extraction && isTextMeaningful(extraction.text, extraction.pageCount)) {
|
|
196
|
+
// Good text extraction — use it directly
|
|
197
|
+
return formatPdfMarkdown(fileName, extraction.text, extraction.pageCount, {
|
|
198
|
+
title: extraction.title,
|
|
199
|
+
author: extraction.author,
|
|
200
|
+
method: "text-extraction",
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
// Step 2: Text is empty/sparse — try OCR (Azure Mistral or direct Mistral)
|
|
204
|
+
const pageCount = extraction?.pageCount ?? 0;
|
|
205
|
+
const sparseText = extraction?.text ?? "";
|
|
206
|
+
try {
|
|
207
|
+
const ocrText = await ocrPdf(pdfPath);
|
|
208
|
+
const config = getOcrConfig();
|
|
209
|
+
return formatPdfMarkdown(fileName, ocrText, pageCount, {
|
|
210
|
+
title: extraction?.title,
|
|
211
|
+
author: extraction?.author,
|
|
212
|
+
method: config?.provider === "azure-mistral" ? "azure-mistral-ocr" : "mistral-ocr",
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
catch (err) {
|
|
216
|
+
const ocrError = err instanceof Error ? err.message : String(err);
|
|
217
|
+
// No OCR available — return whatever we got (possibly empty)
|
|
218
|
+
if (sparseText) {
|
|
219
|
+
return formatPdfMarkdown(fileName, sparseText, pageCount, {
|
|
220
|
+
title: extraction?.title,
|
|
221
|
+
author: extraction?.author,
|
|
222
|
+
method: "text-extraction (partial)",
|
|
223
|
+
warning: `This PDF appears to be scanned/image-based. Text extraction may be incomplete. OCR failed: ${ocrError}`,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
return `# ${fileName}\n\n> ⚠️ This PDF is scanned/image-based and could not be read.\n> Text extraction returned no content.\n> OCR failed: ${ocrError}\n\nSet AZURE_MISTRAL_ENDPOINT + AZURE_MISTRAL_API_KEY or MISTRAL_API_KEY to enable OCR.`;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Format extracted PDF content as clean Markdown.
|
|
231
|
+
*/
|
|
232
|
+
function formatPdfMarkdown(fileName, text, pageCount, opts) {
|
|
233
|
+
const lines = [
|
|
234
|
+
`# ${fileName}`,
|
|
235
|
+
"",
|
|
236
|
+
`> Extracted from PDF · ${pageCount} page${pageCount !== 1 ? "s" : ""} · ${opts.method}`,
|
|
237
|
+
"",
|
|
238
|
+
];
|
|
239
|
+
if (opts.title)
|
|
240
|
+
lines.push(`**Title:** ${opts.title} `);
|
|
241
|
+
if (opts.author)
|
|
242
|
+
lines.push(`**Author:** ${opts.author} `);
|
|
243
|
+
if (opts.title || opts.author)
|
|
244
|
+
lines.push("");
|
|
245
|
+
if (opts.warning) {
|
|
246
|
+
lines.push(`> ⚠️ ${opts.warning}`, "");
|
|
247
|
+
}
|
|
248
|
+
lines.push("---", "", text.trim());
|
|
249
|
+
return lines.join("\n");
|
|
250
|
+
}
|
|
251
|
+
// ---------------------------------------------------------------------------
|
|
252
|
+
// Cache management
|
|
253
|
+
// ---------------------------------------------------------------------------
|
|
254
|
+
/**
|
|
255
|
+
* Get the cache path for a converted file.
|
|
256
|
+
* E.g., `subfolder/invoice.pdf` → `<folderRoot>/.agentxl-cache/subfolder/invoice.pdf.md`
|
|
257
|
+
*/
|
|
258
|
+
function getCachePath(folderRoot, relativePath) {
|
|
259
|
+
return join(folderRoot, CACHE_DIR, `${relativePath}.md`);
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Check if a cached conversion exists and is newer than the source file.
|
|
263
|
+
*/
|
|
264
|
+
function isCacheValid(sourcePath, cachePath) {
|
|
265
|
+
if (!existsSync(cachePath))
|
|
266
|
+
return false;
|
|
267
|
+
try {
|
|
268
|
+
const sourceTime = statSync(sourcePath).mtimeMs;
|
|
269
|
+
const cacheTime = statSync(cachePath).mtimeMs;
|
|
270
|
+
return cacheTime >= sourceTime;
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Pre-convert all PDFs in an inventory to Markdown.
|
|
278
|
+
* Skips files where the cache is still valid (source not modified).
|
|
279
|
+
*
|
|
280
|
+
* @param inventory - Folder inventory from scanner
|
|
281
|
+
* @returns Summary of conversion results
|
|
282
|
+
*/
|
|
283
|
+
export async function convertDocuments(inventory) {
|
|
284
|
+
const result = {
|
|
285
|
+
converted: 0,
|
|
286
|
+
ocrConverted: 0,
|
|
287
|
+
cached: 0,
|
|
288
|
+
failed: 0,
|
|
289
|
+
errors: [],
|
|
290
|
+
};
|
|
291
|
+
const pdfs = inventory.files.filter((f) => f.extension === ".pdf" && f.supported);
|
|
292
|
+
if (pdfs.length === 0)
|
|
293
|
+
return result;
|
|
294
|
+
for (const file of pdfs) {
|
|
295
|
+
const cachePath = getCachePath(inventory.folderPath, file.relativePath);
|
|
296
|
+
// Skip if cache is still valid
|
|
297
|
+
if (isCacheValid(file.absolutePath, cachePath)) {
|
|
298
|
+
result.cached++;
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
try {
|
|
302
|
+
const markdown = await pdfToMarkdown(file.absolutePath);
|
|
303
|
+
// Detect which method was used
|
|
304
|
+
const usedOcr = markdown.includes("mistral-ocr");
|
|
305
|
+
// Ensure cache directory exists
|
|
306
|
+
const cacheDir = dirname(cachePath);
|
|
307
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
308
|
+
writeFileSync(cachePath, markdown, "utf-8");
|
|
309
|
+
if (usedOcr) {
|
|
310
|
+
result.ocrConverted++;
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
result.converted++;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
catch (err) {
|
|
317
|
+
result.failed++;
|
|
318
|
+
result.errors.push(`${file.relativePath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return result;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Get the markdown path for a source file, if it has been converted.
|
|
325
|
+
* Returns null if no cached conversion exists.
|
|
326
|
+
*/
|
|
327
|
+
export function getConvertedPath(folderRoot, relativePath) {
|
|
328
|
+
const cachePath = getCachePath(folderRoot, relativePath);
|
|
329
|
+
return existsSync(cachePath) ? cachePath : null;
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Build a list of converted markdown files for agent context.
|
|
333
|
+
* Returns entries like: `invoice.pdf → .agentxl-cache/invoice.pdf.md`
|
|
334
|
+
*/
|
|
335
|
+
export function listConvertedFiles(inventory) {
|
|
336
|
+
const entries = [];
|
|
337
|
+
for (const file of inventory.files) {
|
|
338
|
+
if (file.extension === ".pdf") {
|
|
339
|
+
const cachePath = getCachePath(inventory.folderPath, file.relativePath);
|
|
340
|
+
if (existsSync(cachePath)) {
|
|
341
|
+
const convertedRelative = relative(inventory.folderPath, cachePath).replace(/\\/g, "/");
|
|
342
|
+
entries.push({
|
|
343
|
+
source: file.relativePath,
|
|
344
|
+
converted: convertedRelative,
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return entries;
|
|
350
|
+
}
|
|
351
|
+
// Exports for testing
|
|
352
|
+
export { isTextMeaningful, getOcrConfig, MIN_CHARS_PER_PAGE };
|
|
353
|
+
//# sourceMappingURL=document-converter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-converter.js","sourceRoot":"","sources":["../../src/server/document-converter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Excel execution bridge — bidirectional communication between
|
|
3
|
+
* server-side tool execution and browser-side Office.js.
|
|
4
|
+
*
|
|
5
|
+
* Flow:
|
|
6
|
+
* 1. Agent calls `excel` custom tool with Office.js code
|
|
7
|
+
* 2. Tool execute() registers a pending execution and waits
|
|
8
|
+
* 3. Pi SDK emits tool_execution_start SSE → taskpane receives it
|
|
9
|
+
* 4. Taskpane runs the code inside Excel.run() via Office.js
|
|
10
|
+
* 5. Taskpane POSTs result to /api/excel/result
|
|
11
|
+
* 6. Bridge resolves the pending promise → tool returns result to agent
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Register a pending Excel execution and return a promise that resolves
|
|
15
|
+
* when the taskpane sends the result back.
|
|
16
|
+
*
|
|
17
|
+
* Called by the `excel` custom tool's execute function.
|
|
18
|
+
*/
|
|
19
|
+
export declare function registerPendingExecution(toolCallId: string, timeoutMs?: number): Promise<string>;
|
|
20
|
+
/**
|
|
21
|
+
* Resolve a pending execution with a successful result.
|
|
22
|
+
* Called when the taskpane POSTs to /api/excel/result.
|
|
23
|
+
*
|
|
24
|
+
* @returns true if the execution was found and resolved.
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolveExecution(toolCallId: string, result: string): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Reject a pending execution with an error.
|
|
29
|
+
* Called when the taskpane reports an Office.js error.
|
|
30
|
+
*
|
|
31
|
+
* @returns true if the execution was found and rejected.
|
|
32
|
+
*/
|
|
33
|
+
export declare function rejectExecution(toolCallId: string, errorMessage: string): boolean;
|
|
34
|
+
/** Get count of pending executions (for diagnostics). */
|
|
35
|
+
export declare function getPendingCount(): number;
|
|
36
|
+
/** Clear all pending executions (for cleanup/testing). */
|
|
37
|
+
export declare function clearAllPending(): void;
|
|
38
|
+
//# sourceMappingURL=excel-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"excel-bridge.d.ts","sourceRoot":"","sources":["../../src/server/excel-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAcH;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,MAA2B,GACrC,OAAO,CAAC,MAAM,CAAC,CAcjB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAQT;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,GACnB,OAAO,CAQT;AAED,yDAAyD;AACzD,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,0DAA0D;AAC1D,wBAAgB,eAAe,IAAI,IAAI,CAMtC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Excel execution bridge — bidirectional communication between
|
|
3
|
+
* server-side tool execution and browser-side Office.js.
|
|
4
|
+
*
|
|
5
|
+
* Flow:
|
|
6
|
+
* 1. Agent calls `excel` custom tool with Office.js code
|
|
7
|
+
* 2. Tool execute() registers a pending execution and waits
|
|
8
|
+
* 3. Pi SDK emits tool_execution_start SSE → taskpane receives it
|
|
9
|
+
* 4. Taskpane runs the code inside Excel.run() via Office.js
|
|
10
|
+
* 5. Taskpane POSTs result to /api/excel/result
|
|
11
|
+
* 6. Bridge resolves the pending promise → tool returns result to agent
|
|
12
|
+
*/
|
|
13
|
+
/** Default timeout for Excel execution (ms). */
|
|
14
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
15
|
+
/** Map of toolCallId → pending execution promise. */
|
|
16
|
+
const pending = new Map();
|
|
17
|
+
/**
|
|
18
|
+
* Register a pending Excel execution and return a promise that resolves
|
|
19
|
+
* when the taskpane sends the result back.
|
|
20
|
+
*
|
|
21
|
+
* Called by the `excel` custom tool's execute function.
|
|
22
|
+
*/
|
|
23
|
+
export function registerPendingExecution(toolCallId, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
24
|
+
return new Promise((resolve, reject) => {
|
|
25
|
+
const timeout = setTimeout(() => {
|
|
26
|
+
pending.delete(toolCallId);
|
|
27
|
+
reject(new Error(`Excel execution timed out after ${timeoutMs / 1000}s. ` +
|
|
28
|
+
`The taskpane may not be connected or Excel may be unresponsive.`));
|
|
29
|
+
}, timeoutMs);
|
|
30
|
+
pending.set(toolCallId, { resolve, reject, timeout });
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Resolve a pending execution with a successful result.
|
|
35
|
+
* Called when the taskpane POSTs to /api/excel/result.
|
|
36
|
+
*
|
|
37
|
+
* @returns true if the execution was found and resolved.
|
|
38
|
+
*/
|
|
39
|
+
export function resolveExecution(toolCallId, result) {
|
|
40
|
+
const entry = pending.get(toolCallId);
|
|
41
|
+
if (!entry)
|
|
42
|
+
return false;
|
|
43
|
+
clearTimeout(entry.timeout);
|
|
44
|
+
pending.delete(toolCallId);
|
|
45
|
+
entry.resolve(result);
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Reject a pending execution with an error.
|
|
50
|
+
* Called when the taskpane reports an Office.js error.
|
|
51
|
+
*
|
|
52
|
+
* @returns true if the execution was found and rejected.
|
|
53
|
+
*/
|
|
54
|
+
export function rejectExecution(toolCallId, errorMessage) {
|
|
55
|
+
const entry = pending.get(toolCallId);
|
|
56
|
+
if (!entry)
|
|
57
|
+
return false;
|
|
58
|
+
clearTimeout(entry.timeout);
|
|
59
|
+
pending.delete(toolCallId);
|
|
60
|
+
entry.reject(new Error(`Excel error: ${errorMessage}`));
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
/** Get count of pending executions (for diagnostics). */
|
|
64
|
+
export function getPendingCount() {
|
|
65
|
+
return pending.size;
|
|
66
|
+
}
|
|
67
|
+
/** Clear all pending executions (for cleanup/testing). */
|
|
68
|
+
export function clearAllPending() {
|
|
69
|
+
for (const [id, entry] of pending) {
|
|
70
|
+
clearTimeout(entry.timeout);
|
|
71
|
+
entry.reject(new Error("Cleared"));
|
|
72
|
+
}
|
|
73
|
+
pending.clear();
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=excel-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"excel-bridge.js","sourceRoot":"","sources":["../../src/server/excel-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,gDAAgD;AAChD,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAQlC,qDAAqD;AACrD,MAAM,OAAO,GAAG,IAAI,GAAG,EAA4B,CAAC;AAEpD;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CACtC,UAAkB,EAClB,YAAoB,kBAAkB;IAEtC,OAAO,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC7C,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC9B,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAC3B,MAAM,CACJ,IAAI,KAAK,CACP,mCAAmC,SAAS,GAAG,IAAI,KAAK;gBACtD,iEAAiE,CACpE,CACF,CAAC;QACJ,CAAC,EAAE,SAAS,CAAC,CAAC;QAEd,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,UAAkB,EAClB,MAAc;IAEd,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACtC,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IAEzB,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC5B,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAC3B,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACtB,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAC7B,UAAkB,EAClB,YAAoB;IAEpB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACtC,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IAEzB,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC5B,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAC3B,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,gBAAgB,YAAY,EAAE,CAAC,CAAC,CAAC;IACxD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,eAAe;IAC7B,OAAO,OAAO,CAAC,IAAI,CAAC;AACtB,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,eAAe;IAC7B,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,OAAO,EAAE,CAAC;QAClC,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC5B,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,CAAC,KAAK,EAAE,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface FolderPickerStrategy {
|
|
2
|
+
platform: string;
|
|
3
|
+
method: "native-helper" | "powershell" | "osascript" | "manual-only";
|
|
4
|
+
helperPath: string | null;
|
|
5
|
+
}
|
|
6
|
+
/** Detect which folder picker strategy will be used at runtime. */
|
|
7
|
+
export declare function getFolderPickerStrategy(): FolderPickerStrategy;
|
|
8
|
+
export declare function pickLocalFolder(initialPath?: string | null): Promise<string | null>;
|
|
9
|
+
//# sourceMappingURL=folder-picker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"folder-picker.d.ts","sourceRoot":"","sources":["../../src/server/folder-picker.ts"],"names":[],"mappings":"AAyOA,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,eAAe,GAAG,YAAY,GAAG,WAAW,GAAG,aAAa,CAAC;IACrE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,mEAAmE;AACnE,wBAAgB,uBAAuB,IAAI,oBAAoB,CAgB9D;AAED,wBAAsB,eAAe,CACnC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GAC1B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiExB"}
|