@arbidocs/sdk 0.3.10 → 0.3.13
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/browser-BszYf6lU.d.cts +3183 -0
- package/dist/browser-BszYf6lU.d.ts +3183 -0
- package/dist/browser.cjs +185 -30
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +1 -1
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +183 -26
- package/dist/browser.js.map +1 -1
- package/dist/index.cjs +393 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +40 -2971
- package/dist/index.d.ts +40 -2971
- package/dist/index.js +388 -28
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
|
-
import
|
|
2
|
+
import path2 from 'path';
|
|
3
3
|
import os from 'os';
|
|
4
4
|
import { createArbiClient, base64ToBytes, deriveEncryptionKeypairFromSigning, sealedBoxDecrypt, createWorkspaceKeyHeader, buildWebSocketUrl, createAuthMessage, parseServerMessage, isMessageType } from '@arbidocs/client';
|
|
5
5
|
|
|
@@ -36,14 +36,64 @@ function requireOk(result, message) {
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
function getErrorMessage(err) {
|
|
39
|
-
|
|
39
|
+
if (!(err instanceof Error)) return String(err);
|
|
40
|
+
const rootCause = getDeepestCause(err);
|
|
41
|
+
if (rootCause !== err) {
|
|
42
|
+
const rootMsg = rootCause.message || String(rootCause);
|
|
43
|
+
if (err.message && !err.message.includes(rootMsg)) {
|
|
44
|
+
return `${err.message}: ${rootMsg}`;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return err.message;
|
|
48
|
+
}
|
|
49
|
+
function getDeepestCause(err) {
|
|
50
|
+
let current = err;
|
|
51
|
+
const seen = /* @__PURE__ */ new Set();
|
|
52
|
+
while (current.cause instanceof Error && !seen.has(current.cause)) {
|
|
53
|
+
seen.add(current);
|
|
54
|
+
current = current.cause;
|
|
55
|
+
}
|
|
56
|
+
return current;
|
|
57
|
+
}
|
|
58
|
+
function getErrorCode(err) {
|
|
59
|
+
if (!(err instanceof Error)) return void 0;
|
|
60
|
+
let current = err;
|
|
61
|
+
const seen = /* @__PURE__ */ new Set();
|
|
62
|
+
while (current && !seen.has(current)) {
|
|
63
|
+
seen.add(current);
|
|
64
|
+
const code = current.code;
|
|
65
|
+
if (typeof code === "string") return code;
|
|
66
|
+
current = current.cause instanceof Error ? current.cause : void 0;
|
|
67
|
+
}
|
|
68
|
+
return void 0;
|
|
40
69
|
}
|
|
41
70
|
|
|
42
71
|
// src/fetch.ts
|
|
43
|
-
var
|
|
72
|
+
var STATUS_FALLBACKS = {
|
|
44
73
|
401: "Token has expired. Please run: arbi login",
|
|
74
|
+
403: "Access denied. You may not have permission for this workspace.",
|
|
75
|
+
404: "Resource not found.",
|
|
45
76
|
503: "The selected LLM is not responding. Please retry or select another model."
|
|
46
77
|
};
|
|
78
|
+
async function extractErrorMessage(res) {
|
|
79
|
+
let bodyDetail;
|
|
80
|
+
try {
|
|
81
|
+
const text = await res.text();
|
|
82
|
+
if (text) {
|
|
83
|
+
try {
|
|
84
|
+
const json = JSON.parse(text);
|
|
85
|
+
bodyDetail = json.detail || json.message || json.error || void 0;
|
|
86
|
+
} catch {
|
|
87
|
+
if (text.length < 200) bodyDetail = text;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
} catch {
|
|
91
|
+
}
|
|
92
|
+
if (bodyDetail) return `Request failed (${res.status}): ${bodyDetail}`;
|
|
93
|
+
const fallback = STATUS_FALLBACKS[res.status];
|
|
94
|
+
if (fallback) return fallback;
|
|
95
|
+
return `Request failed: ${res.status} ${res.statusText}`;
|
|
96
|
+
}
|
|
47
97
|
async function authenticatedFetch(options) {
|
|
48
98
|
const { baseUrl, accessToken, workspaceKeyHeader, path: path3, method, body, headers } = options;
|
|
49
99
|
const res = await fetch(`${baseUrl}${path3}`, {
|
|
@@ -56,16 +106,15 @@ async function authenticatedFetch(options) {
|
|
|
56
106
|
body
|
|
57
107
|
});
|
|
58
108
|
if (!res.ok) {
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
const text = await res.text().catch(() => "");
|
|
62
|
-
throw new Error(`Request failed: ${res.status} ${text}`);
|
|
109
|
+
const message = await extractErrorMessage(res);
|
|
110
|
+
throw new ArbiApiError(message, { status: res.status, statusText: res.statusText });
|
|
63
111
|
}
|
|
64
112
|
return res;
|
|
65
113
|
}
|
|
66
114
|
var DEFAULT_SESSION = {
|
|
67
115
|
lastMessageExtId: null,
|
|
68
|
-
conversationExtId: null
|
|
116
|
+
conversationExtId: null,
|
|
117
|
+
workspaceId: null
|
|
69
118
|
};
|
|
70
119
|
var FileConfigStore = class {
|
|
71
120
|
configDir;
|
|
@@ -73,10 +122,10 @@ var FileConfigStore = class {
|
|
|
73
122
|
credentialsFile;
|
|
74
123
|
sessionFile;
|
|
75
124
|
constructor(configDir) {
|
|
76
|
-
this.configDir = configDir ?? process.env.ARBI_CONFIG_DIR ??
|
|
77
|
-
this.configFile =
|
|
78
|
-
this.credentialsFile =
|
|
79
|
-
this.sessionFile =
|
|
125
|
+
this.configDir = configDir ?? process.env.ARBI_CONFIG_DIR ?? path2.join(os.homedir(), ".arbi");
|
|
126
|
+
this.configFile = path2.join(this.configDir, "config.json");
|
|
127
|
+
this.credentialsFile = path2.join(this.configDir, "credentials.json");
|
|
128
|
+
this.sessionFile = path2.join(this.configDir, "session.json");
|
|
80
129
|
}
|
|
81
130
|
ensureConfigDir() {
|
|
82
131
|
if (!fs.existsSync(this.configDir)) {
|
|
@@ -147,6 +196,77 @@ var FileConfigStore = class {
|
|
|
147
196
|
clearChatSession() {
|
|
148
197
|
this.saveChatSession({ ...DEFAULT_SESSION });
|
|
149
198
|
}
|
|
199
|
+
/**
|
|
200
|
+
* Try to resolve config from multiple sources, in priority order:
|
|
201
|
+
*
|
|
202
|
+
* 1. Existing `~/.arbi/config.json` (highest priority)
|
|
203
|
+
* 2. `ARBI_SERVER_URL` environment variable
|
|
204
|
+
* 3. `.env` file in `searchDir` → read `VITE_DEPLOYMENT_DOMAIN`
|
|
205
|
+
* 4. `public/config.json` in `searchDir` → read `deployment.domain`
|
|
206
|
+
* 5. Default to `https://localhost`
|
|
207
|
+
*
|
|
208
|
+
* Returns `{ config, source }` where source describes where the config came from.
|
|
209
|
+
* Saves auto-detected config to disk so subsequent calls use the fast path.
|
|
210
|
+
*/
|
|
211
|
+
resolveConfigWithFallbacks(searchDir) {
|
|
212
|
+
const existing = this.getConfig();
|
|
213
|
+
if (existing?.baseUrl) {
|
|
214
|
+
return { config: existing, source: "config" };
|
|
215
|
+
}
|
|
216
|
+
const envUrl = process.env.ARBI_SERVER_URL;
|
|
217
|
+
if (envUrl) {
|
|
218
|
+
const domain = new URL(envUrl).hostname;
|
|
219
|
+
const config2 = { baseUrl: envUrl.replace(/\/$/, ""), deploymentDomain: domain };
|
|
220
|
+
this.saveConfig(config2);
|
|
221
|
+
return { config: config2, source: "ARBI_SERVER_URL env var" };
|
|
222
|
+
}
|
|
223
|
+
const dir = searchDir || process.cwd();
|
|
224
|
+
const dotenvConfig = this.readDotEnvDomain(path2.join(dir, ".env"));
|
|
225
|
+
if (dotenvConfig) {
|
|
226
|
+
this.saveConfig(dotenvConfig);
|
|
227
|
+
return { config: dotenvConfig, source: ".env file" };
|
|
228
|
+
}
|
|
229
|
+
const publicConfig = this.readPublicConfigDomain(path2.join(dir, "public", "config.json"));
|
|
230
|
+
if (publicConfig) {
|
|
231
|
+
this.saveConfig(publicConfig);
|
|
232
|
+
return { config: publicConfig, source: "public/config.json" };
|
|
233
|
+
}
|
|
234
|
+
const config = { baseUrl: "https://localhost", deploymentDomain: "localhost" };
|
|
235
|
+
this.saveConfig(config);
|
|
236
|
+
return { config, source: "default (https://localhost)" };
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Read VITE_DEPLOYMENT_DOMAIN from a .env file.
|
|
240
|
+
*/
|
|
241
|
+
readDotEnvDomain(filePath) {
|
|
242
|
+
try {
|
|
243
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
244
|
+
const match = content.match(/^VITE_DEPLOYMENT_DOMAIN\s*=\s*(.+)$/m);
|
|
245
|
+
if (match) {
|
|
246
|
+
const domain = match[1].trim().replace(/^["']|["']$/g, "");
|
|
247
|
+
if (domain) {
|
|
248
|
+
return { baseUrl: `https://${domain}`, deploymentDomain: domain };
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
} catch {
|
|
252
|
+
}
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Read deployment.domain from a public/config.json file.
|
|
257
|
+
*/
|
|
258
|
+
readPublicConfigDomain(filePath) {
|
|
259
|
+
try {
|
|
260
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
261
|
+
const json = JSON.parse(content);
|
|
262
|
+
const domain = json?.deployment?.domain;
|
|
263
|
+
if (domain) {
|
|
264
|
+
return { baseUrl: `https://${domain}`, deploymentDomain: domain };
|
|
265
|
+
}
|
|
266
|
+
} catch {
|
|
267
|
+
}
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
150
270
|
};
|
|
151
271
|
function formatWorkspaceChoices(wsList) {
|
|
152
272
|
return wsList.map((ws) => {
|
|
@@ -172,7 +292,11 @@ async function createAuthenticatedClient(config, creds, store) {
|
|
|
172
292
|
});
|
|
173
293
|
store.saveCredentials({
|
|
174
294
|
...creds,
|
|
175
|
-
serverSessionKeyBase64: arbi.crypto.bytesToBase64(loginResult.serverSessionKey)
|
|
295
|
+
serverSessionKeyBase64: arbi.crypto.bytesToBase64(loginResult.serverSessionKey),
|
|
296
|
+
accessToken: void 0,
|
|
297
|
+
workspaceKeyHeader: void 0,
|
|
298
|
+
workspaceId: void 0,
|
|
299
|
+
tokenTimestamp: void 0
|
|
176
300
|
});
|
|
177
301
|
return { arbi, loginResult };
|
|
178
302
|
}
|
|
@@ -187,7 +311,12 @@ async function performPasswordLogin(config, email, password, store) {
|
|
|
187
311
|
store.saveCredentials({
|
|
188
312
|
email,
|
|
189
313
|
signingPrivateKeyBase64: arbi.crypto.bytesToBase64(loginResult.signingPrivateKey),
|
|
190
|
-
serverSessionKeyBase64: arbi.crypto.bytesToBase64(loginResult.serverSessionKey)
|
|
314
|
+
serverSessionKeyBase64: arbi.crypto.bytesToBase64(loginResult.serverSessionKey),
|
|
315
|
+
// Clear any cached workspace tokens — new session key invalidates them
|
|
316
|
+
accessToken: void 0,
|
|
317
|
+
workspaceKeyHeader: void 0,
|
|
318
|
+
workspaceId: void 0,
|
|
319
|
+
tokenTimestamp: void 0
|
|
191
320
|
});
|
|
192
321
|
return { arbi, loginResult, config };
|
|
193
322
|
}
|
|
@@ -250,6 +379,10 @@ async function resolveAuth(store) {
|
|
|
250
379
|
const { arbi, loginResult } = await createAuthenticatedClient(config, creds, store);
|
|
251
380
|
return { arbi, loginResult, config };
|
|
252
381
|
}
|
|
382
|
+
var TOKEN_MAX_AGE_MS = 50 * 60 * 1e3;
|
|
383
|
+
function isCachedTokenValid(creds, workspaceId) {
|
|
384
|
+
return !!(creds.accessToken && creds.workspaceKeyHeader && creds.workspaceId === workspaceId && creds.tokenTimestamp && Date.now() - new Date(creds.tokenTimestamp).getTime() < TOKEN_MAX_AGE_MS);
|
|
385
|
+
}
|
|
253
386
|
async function resolveWorkspace(store, workspaceOpt) {
|
|
254
387
|
const config = store.requireConfig();
|
|
255
388
|
const creds = store.requireCredentials();
|
|
@@ -257,6 +390,32 @@ async function resolveWorkspace(store, workspaceOpt) {
|
|
|
257
390
|
if (!workspaceId) {
|
|
258
391
|
throw new ArbiError("No workspace selected. Run: arbi workspace select <id>");
|
|
259
392
|
}
|
|
393
|
+
if (isCachedTokenValid(creds, workspaceId)) {
|
|
394
|
+
const arbi2 = createArbiClient({
|
|
395
|
+
baseUrl: config.baseUrl,
|
|
396
|
+
deploymentDomain: config.deploymentDomain,
|
|
397
|
+
credentials: "omit"
|
|
398
|
+
});
|
|
399
|
+
await arbi2.crypto.initSodium();
|
|
400
|
+
arbi2.session.setSelectedWorkspace(workspaceId);
|
|
401
|
+
arbi2.session.setAccessToken(creds.accessToken);
|
|
402
|
+
arbi2.session.setCachedWorkspaceHeader(workspaceId, creds.workspaceKeyHeader);
|
|
403
|
+
const signingPrivateKey = base64ToBytes(creds.signingPrivateKeyBase64);
|
|
404
|
+
const serverSessionKey = base64ToBytes(creds.serverSessionKeyBase64);
|
|
405
|
+
const loginResult2 = {
|
|
406
|
+
accessToken: creds.accessToken,
|
|
407
|
+
signingPrivateKey,
|
|
408
|
+
serverSessionKey
|
|
409
|
+
};
|
|
410
|
+
return {
|
|
411
|
+
arbi: arbi2,
|
|
412
|
+
loginResult: loginResult2,
|
|
413
|
+
config,
|
|
414
|
+
workspaceId,
|
|
415
|
+
accessToken: creds.accessToken,
|
|
416
|
+
workspaceKeyHeader: creds.workspaceKeyHeader
|
|
417
|
+
};
|
|
418
|
+
}
|
|
260
419
|
const { arbi, loginResult } = await createAuthenticatedClient(config, creds, store);
|
|
261
420
|
await selectWorkspaceById(
|
|
262
421
|
arbi,
|
|
@@ -269,10 +428,57 @@ async function resolveWorkspace(store, workspaceOpt) {
|
|
|
269
428
|
if (!accessToken || !workspaceKeyHeader) {
|
|
270
429
|
throw new ArbiError("Authentication error \u2014 missing token or workspace key");
|
|
271
430
|
}
|
|
431
|
+
store.saveCredentials({
|
|
432
|
+
...store.requireCredentials(),
|
|
433
|
+
accessToken,
|
|
434
|
+
workspaceKeyHeader,
|
|
435
|
+
workspaceId,
|
|
436
|
+
tokenTimestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
437
|
+
});
|
|
272
438
|
return { arbi, loginResult, config, workspaceId, accessToken, workspaceKeyHeader };
|
|
273
439
|
}
|
|
274
440
|
|
|
275
441
|
// src/sse.ts
|
|
442
|
+
var TOOL_LABELS = {
|
|
443
|
+
search_documents: "Searching documents",
|
|
444
|
+
get_document_passages: "Reading document",
|
|
445
|
+
get_table_of_contents: "Getting table of contents",
|
|
446
|
+
view_document_pages: "Viewing document pages",
|
|
447
|
+
get_full_document: "Reading full document",
|
|
448
|
+
web_search: "Searching the web",
|
|
449
|
+
read_url: "Reading web pages",
|
|
450
|
+
ask_user: "Asking user",
|
|
451
|
+
compaction: "Compacting conversation",
|
|
452
|
+
personal_agent: "Running agent",
|
|
453
|
+
create_artifact: "Creating artifact",
|
|
454
|
+
create_plan: "Creating plan",
|
|
455
|
+
save_skill: "Saving skill",
|
|
456
|
+
run_code: "Running code"
|
|
457
|
+
};
|
|
458
|
+
var LIFECYCLE_LABELS = {
|
|
459
|
+
evaluation: "Evaluating results",
|
|
460
|
+
answering: "Writing answer",
|
|
461
|
+
reviewing: "Reviewing answer",
|
|
462
|
+
planning: "Planning",
|
|
463
|
+
tool_progress: "Working"
|
|
464
|
+
};
|
|
465
|
+
function formatAgentStepLabel(step) {
|
|
466
|
+
if (step.focus) return step.focus;
|
|
467
|
+
const detail = step.detail;
|
|
468
|
+
if (step.step === "tool_progress" && detail && detail.length > 0) {
|
|
469
|
+
const toolName = detail[0].tool;
|
|
470
|
+
const label = toolName && TOOL_LABELS[toolName] || LIFECYCLE_LABELS.tool_progress;
|
|
471
|
+
const message = detail[0].message;
|
|
472
|
+
return message ? `${label}: ${message}` : label;
|
|
473
|
+
}
|
|
474
|
+
if (step.step) {
|
|
475
|
+
return LIFECYCLE_LABELS[step.step] || step.step;
|
|
476
|
+
}
|
|
477
|
+
if (detail && detail.length > 0 && detail[0].tool) {
|
|
478
|
+
return TOOL_LABELS[detail[0].tool] || detail[0].tool;
|
|
479
|
+
}
|
|
480
|
+
return "";
|
|
481
|
+
}
|
|
276
482
|
function parseSSEEvents(chunk, buffer) {
|
|
277
483
|
const combined = buffer + chunk;
|
|
278
484
|
const events = [];
|
|
@@ -343,6 +549,11 @@ async function streamSSE(response, callbacks = {}) {
|
|
|
343
549
|
usage = data.response.usage;
|
|
344
550
|
callbacks.onUsage?.(data.response.usage);
|
|
345
551
|
}
|
|
552
|
+
if (data.response?.metadata) {
|
|
553
|
+
const meta = data.response.metadata;
|
|
554
|
+
metadata = meta;
|
|
555
|
+
callbacks.onMetadata?.(meta);
|
|
556
|
+
}
|
|
346
557
|
if (data.t != null) callbacks.onElapsedTime?.(data.t);
|
|
347
558
|
callbacks.onComplete?.();
|
|
348
559
|
},
|
|
@@ -355,8 +566,8 @@ async function streamSSE(response, callbacks = {}) {
|
|
|
355
566
|
// ARBI-specific events (dot-prefixed from server)
|
|
356
567
|
"arbi.agent_step": (raw) => {
|
|
357
568
|
const data = JSON.parse(raw);
|
|
358
|
-
const
|
|
359
|
-
if (
|
|
569
|
+
const label = formatAgentStepLabel(data);
|
|
570
|
+
if (label) agentSteps.push(label);
|
|
360
571
|
callbacks.onAgentStep?.(data);
|
|
361
572
|
if (data.t != null) callbacks.onElapsedTime?.(data.t);
|
|
362
573
|
},
|
|
@@ -634,16 +845,34 @@ function formatUserName(user) {
|
|
|
634
845
|
// src/operations/documents.ts
|
|
635
846
|
var documents_exports = {};
|
|
636
847
|
__export(documents_exports, {
|
|
848
|
+
SUPPORTED_EXTENSIONS: () => SUPPORTED_EXTENSIONS,
|
|
637
849
|
deleteDocuments: () => deleteDocuments,
|
|
638
850
|
downloadDocument: () => downloadDocument,
|
|
639
851
|
getDocuments: () => getDocuments,
|
|
640
852
|
getParsedContent: () => getParsedContent,
|
|
641
853
|
listDocuments: () => listDocuments,
|
|
854
|
+
sanitizeFolderPath: () => sanitizeFolderPath,
|
|
642
855
|
updateDocuments: () => updateDocuments,
|
|
643
856
|
uploadFile: () => uploadFile,
|
|
644
|
-
|
|
857
|
+
uploadFiles: () => uploadFiles,
|
|
645
858
|
uploadUrl: () => uploadUrl
|
|
646
859
|
});
|
|
860
|
+
var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
861
|
+
".pdf",
|
|
862
|
+
".txt",
|
|
863
|
+
".md",
|
|
864
|
+
".html",
|
|
865
|
+
".doc",
|
|
866
|
+
".docx",
|
|
867
|
+
".rtf",
|
|
868
|
+
".ppt",
|
|
869
|
+
".pptx",
|
|
870
|
+
".xls",
|
|
871
|
+
".xlsx"
|
|
872
|
+
]);
|
|
873
|
+
function sanitizeFolderPath(folderPath) {
|
|
874
|
+
return folderPath.replace(/[^a-zA-Z0-9_\-/]/g, "_").replace(/_{2,}/g, "_");
|
|
875
|
+
}
|
|
647
876
|
async function listDocuments(arbi) {
|
|
648
877
|
return requireData(await arbi.fetch.GET("/v1/document/list"), "Failed to fetch documents");
|
|
649
878
|
}
|
|
@@ -682,22 +911,31 @@ async function getParsedContent(auth, docId, stage) {
|
|
|
682
911
|
});
|
|
683
912
|
return res.json();
|
|
684
913
|
}
|
|
685
|
-
async function uploadFile(auth, workspaceId, fileData, fileName) {
|
|
914
|
+
async function uploadFile(auth, workspaceId, fileData, fileName, options) {
|
|
686
915
|
const formData = new FormData();
|
|
687
916
|
formData.append("files", fileData, fileName);
|
|
917
|
+
const params = new URLSearchParams({ workspace_ext_id: workspaceId });
|
|
918
|
+
if (options?.folder) params.set("folder", sanitizeFolderPath(options.folder));
|
|
688
919
|
const res = await authenticatedFetch({
|
|
689
920
|
...auth,
|
|
690
|
-
path: `/v1/document/upload
|
|
921
|
+
path: `/v1/document/upload?${params.toString()}`,
|
|
691
922
|
method: "POST",
|
|
692
923
|
body: formData
|
|
693
924
|
});
|
|
694
925
|
return res.json();
|
|
695
926
|
}
|
|
696
|
-
async function
|
|
697
|
-
const
|
|
698
|
-
const
|
|
699
|
-
const
|
|
700
|
-
|
|
927
|
+
async function uploadFiles(auth, workspaceId, files, options) {
|
|
928
|
+
const formData = new FormData();
|
|
929
|
+
for (const f of files) formData.append("files", f.data, f.name);
|
|
930
|
+
const params = new URLSearchParams({ workspace_ext_id: workspaceId });
|
|
931
|
+
if (options?.folder) params.set("folder", sanitizeFolderPath(options.folder));
|
|
932
|
+
const res = await authenticatedFetch({
|
|
933
|
+
...auth,
|
|
934
|
+
path: `/v1/document/upload?${params.toString()}`,
|
|
935
|
+
method: "POST",
|
|
936
|
+
body: formData
|
|
937
|
+
});
|
|
938
|
+
return res.json();
|
|
701
939
|
}
|
|
702
940
|
async function downloadDocument(auth, docId) {
|
|
703
941
|
return authenticatedFetch({
|
|
@@ -897,6 +1135,8 @@ async function retrieve(options) {
|
|
|
897
1135
|
input: query,
|
|
898
1136
|
workspace_ext_id: workspaceId,
|
|
899
1137
|
stream: false,
|
|
1138
|
+
background: false,
|
|
1139
|
+
store: true,
|
|
900
1140
|
tools,
|
|
901
1141
|
...model ? { model } : {}
|
|
902
1142
|
};
|
|
@@ -912,6 +1152,8 @@ async function queryAssistant(options) {
|
|
|
912
1152
|
input: question,
|
|
913
1153
|
workspace_ext_id: workspaceId,
|
|
914
1154
|
stream: true,
|
|
1155
|
+
background: false,
|
|
1156
|
+
store: true,
|
|
915
1157
|
tools: {
|
|
916
1158
|
retrieval_chunk: buildRetrievalChunkTool(docIds),
|
|
917
1159
|
retrieval_full_context: buildRetrievalFullContextTool([])
|
|
@@ -1371,11 +1613,12 @@ var Arbi = class {
|
|
|
1371
1613
|
workspaceId ?? this.requireWorkspace(),
|
|
1372
1614
|
shared
|
|
1373
1615
|
),
|
|
1374
|
-
uploadFile: (fileData, fileName,
|
|
1616
|
+
uploadFile: (fileData, fileName, options) => uploadFile(
|
|
1375
1617
|
this.getAuthHeaders(),
|
|
1376
|
-
workspaceId ?? this.requireWorkspace(),
|
|
1618
|
+
options?.workspaceId ?? this.requireWorkspace(),
|
|
1377
1619
|
fileData,
|
|
1378
|
-
fileName
|
|
1620
|
+
fileName,
|
|
1621
|
+
options?.folder ? { folder: options.folder } : void 0
|
|
1379
1622
|
),
|
|
1380
1623
|
download: (docId) => downloadDocument(this.getAuthHeaders(), docId),
|
|
1381
1624
|
getParsedContent: (docId, stage) => getParsedContent(this.getAuthHeaders(), docId, stage)
|
|
@@ -1517,6 +1760,123 @@ var Arbi = class {
|
|
|
1517
1760
|
}
|
|
1518
1761
|
};
|
|
1519
1762
|
|
|
1520
|
-
|
|
1763
|
+
// src/operations/documents-node.ts
|
|
1764
|
+
var documents_node_exports = {};
|
|
1765
|
+
__export(documents_node_exports, {
|
|
1766
|
+
uploadDirectory: () => uploadDirectory,
|
|
1767
|
+
uploadLocalFile: () => uploadLocalFile,
|
|
1768
|
+
uploadZip: () => uploadZip
|
|
1769
|
+
});
|
|
1770
|
+
function collectFiles(dirPath, baseDir) {
|
|
1771
|
+
const root = baseDir ?? dirPath;
|
|
1772
|
+
const results = [];
|
|
1773
|
+
for (const entry of fs.readdirSync(dirPath, { withFileTypes: true })) {
|
|
1774
|
+
const fullPath = path2.join(dirPath, entry.name);
|
|
1775
|
+
if (entry.isDirectory()) {
|
|
1776
|
+
results.push(...collectFiles(fullPath, root));
|
|
1777
|
+
} else if (entry.isFile()) {
|
|
1778
|
+
const ext = path2.extname(entry.name).toLowerCase();
|
|
1779
|
+
if (SUPPORTED_EXTENSIONS.has(ext)) {
|
|
1780
|
+
results.push({ absolutePath: fullPath, relativePath: path2.relative(root, fullPath) });
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
return results;
|
|
1785
|
+
}
|
|
1786
|
+
async function uploadLocalFile(auth, workspaceId, filePath, options) {
|
|
1787
|
+
const fileBuffer = fs.readFileSync(filePath);
|
|
1788
|
+
const fileName = path2.basename(filePath);
|
|
1789
|
+
const result = await uploadFile(auth, workspaceId, new Blob([fileBuffer]), fileName, options);
|
|
1790
|
+
return { ...result, fileName };
|
|
1791
|
+
}
|
|
1792
|
+
async function uploadDirectory(auth, workspaceId, dirPath) {
|
|
1793
|
+
const resolvedDir = path2.resolve(dirPath);
|
|
1794
|
+
const dirName = path2.basename(resolvedDir);
|
|
1795
|
+
const entries = collectFiles(resolvedDir);
|
|
1796
|
+
if (entries.length === 0) {
|
|
1797
|
+
return { doc_ext_ids: [], duplicates: [], folders: /* @__PURE__ */ new Map() };
|
|
1798
|
+
}
|
|
1799
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1800
|
+
for (const entry of entries) {
|
|
1801
|
+
const relDir = path2.dirname(entry.relativePath);
|
|
1802
|
+
const folder = relDir === "." ? dirName : `${dirName}/${relDir}`;
|
|
1803
|
+
if (!groups.has(folder)) groups.set(folder, []);
|
|
1804
|
+
groups.get(folder).push({ absolutePath: entry.absolutePath, name: path2.basename(entry.relativePath) });
|
|
1805
|
+
}
|
|
1806
|
+
const allDocIds = [];
|
|
1807
|
+
const allDuplicates = [];
|
|
1808
|
+
const folders = /* @__PURE__ */ new Map();
|
|
1809
|
+
for (const [folder, files] of groups) {
|
|
1810
|
+
const blobs = files.map((f) => ({
|
|
1811
|
+
data: new Blob([fs.readFileSync(f.absolutePath)]),
|
|
1812
|
+
name: f.name
|
|
1813
|
+
}));
|
|
1814
|
+
const result = await uploadFiles(auth, workspaceId, blobs, { folder });
|
|
1815
|
+
const dups = result.duplicates ?? [];
|
|
1816
|
+
allDocIds.push(...result.doc_ext_ids);
|
|
1817
|
+
allDuplicates.push(...dups);
|
|
1818
|
+
folders.set(folder, {
|
|
1819
|
+
fileCount: files.length,
|
|
1820
|
+
doc_ext_ids: result.doc_ext_ids,
|
|
1821
|
+
duplicates: dups
|
|
1822
|
+
});
|
|
1823
|
+
}
|
|
1824
|
+
return { doc_ext_ids: allDocIds, duplicates: allDuplicates, folders };
|
|
1825
|
+
}
|
|
1826
|
+
async function uploadZip(auth, workspaceId, zipPath) {
|
|
1827
|
+
const JSZip = (await import('jszip')).default;
|
|
1828
|
+
const zipBuffer = fs.readFileSync(zipPath);
|
|
1829
|
+
const zip = await JSZip.loadAsync(zipBuffer);
|
|
1830
|
+
const zipBaseName = path2.basename(zipPath).replace(/\.zip$/i, "");
|
|
1831
|
+
const entries = [];
|
|
1832
|
+
zip.forEach((relativePath, zipEntry) => {
|
|
1833
|
+
if (zipEntry.dir) return;
|
|
1834
|
+
const ext = path2.extname(relativePath).toLowerCase();
|
|
1835
|
+
if (SUPPORTED_EXTENSIONS.has(ext)) {
|
|
1836
|
+
entries.push({ zipEntryPath: relativePath, zipEntry });
|
|
1837
|
+
}
|
|
1838
|
+
});
|
|
1839
|
+
if (entries.length === 0) {
|
|
1840
|
+
return { doc_ext_ids: [], duplicates: [], folders: /* @__PURE__ */ new Map() };
|
|
1841
|
+
}
|
|
1842
|
+
const firstParts = new Set(entries.map((e) => e.zipEntryPath.split("/")[0]));
|
|
1843
|
+
const hasSingleRoot = firstParts.size === 1 && entries.every((e) => e.zipEntryPath.includes("/"));
|
|
1844
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1845
|
+
for (const entry of entries) {
|
|
1846
|
+
const data = await entry.zipEntry.async("uint8array");
|
|
1847
|
+
const fileName = path2.basename(entry.zipEntryPath);
|
|
1848
|
+
const relDir = path2.dirname(entry.zipEntryPath);
|
|
1849
|
+
let folder;
|
|
1850
|
+
if (hasSingleRoot) {
|
|
1851
|
+
folder = relDir === "." ? zipBaseName : relDir;
|
|
1852
|
+
} else {
|
|
1853
|
+
folder = relDir === "." ? zipBaseName : `${zipBaseName}/${relDir}`;
|
|
1854
|
+
}
|
|
1855
|
+
folder = sanitizeFolderPath(folder);
|
|
1856
|
+
if (!groups.has(folder)) groups.set(folder, []);
|
|
1857
|
+
groups.get(folder).push({ name: fileName, data });
|
|
1858
|
+
}
|
|
1859
|
+
const allDocIds = [];
|
|
1860
|
+
const allDuplicates = [];
|
|
1861
|
+
const folders = /* @__PURE__ */ new Map();
|
|
1862
|
+
for (const [folder, files] of groups) {
|
|
1863
|
+
const blobs = files.map((f) => ({
|
|
1864
|
+
data: new Blob([f.data]),
|
|
1865
|
+
name: f.name
|
|
1866
|
+
}));
|
|
1867
|
+
const result = await uploadFiles(auth, workspaceId, blobs, { folder });
|
|
1868
|
+
const dups = result.duplicates ?? [];
|
|
1869
|
+
allDocIds.push(...result.doc_ext_ids);
|
|
1870
|
+
allDuplicates.push(...dups);
|
|
1871
|
+
folders.set(folder, {
|
|
1872
|
+
fileCount: files.length,
|
|
1873
|
+
doc_ext_ids: result.doc_ext_ids,
|
|
1874
|
+
duplicates: dups
|
|
1875
|
+
});
|
|
1876
|
+
}
|
|
1877
|
+
return { doc_ext_ids: allDocIds, duplicates: allDuplicates, folders };
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
export { Arbi, ArbiApiError, ArbiError, FileConfigStore, LIFECYCLE_LABELS, TOOL_LABELS, agentconfig_exports as agentconfig, assistant_exports as assistant, authenticatedFetch, buildRetrievalChunkTool, buildRetrievalFullContextTool, buildRetrievalTocTool, connectWebSocket, connectWithReconnect, consumeSSEStream, contacts_exports as contacts, conversations_exports as conversations, createAuthenticatedClient, createDocumentWaiter, dm_exports as dm, doctags_exports as doctags, documents_exports as documents, documents_node_exports as documentsNode, files_exports as files, formatAgentStepLabel, formatFileSize, formatUserName, formatWorkspaceChoices, formatWsMessage, generateEncryptedWorkspaceKey, getErrorCode, getErrorMessage, health_exports as health, parseSSEEvents, performPasswordLogin, requireData, requireOk, resolveAuth, resolveWorkspace, selectWorkspace, selectWorkspaceById, settings_exports as settings, streamSSE, tags_exports as tags, workspaces_exports as workspaces };
|
|
1521
1881
|
//# sourceMappingURL=index.js.map
|
|
1522
1882
|
//# sourceMappingURL=index.js.map
|