@arbidocs/sdk 0.3.11 → 0.3.14

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/index.cjs CHANGED
@@ -1,14 +1,14 @@
1
1
  'use strict';
2
2
 
3
3
  var fs = require('fs');
4
- var path = require('path');
4
+ var path2 = require('path');
5
5
  var os = require('os');
6
6
  var client = require('@arbidocs/client');
7
7
 
8
8
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
9
 
10
10
  var fs__default = /*#__PURE__*/_interopDefault(fs);
11
- var path__default = /*#__PURE__*/_interopDefault(path);
11
+ var path2__default = /*#__PURE__*/_interopDefault(path2);
12
12
  var os__default = /*#__PURE__*/_interopDefault(os);
13
13
 
14
14
  var __defProp = Object.defineProperty;
@@ -44,7 +44,36 @@ function requireOk(result, message) {
44
44
  }
45
45
  }
46
46
  function getErrorMessage(err) {
47
- return err instanceof Error ? err.message : String(err);
47
+ if (!(err instanceof Error)) return String(err);
48
+ const rootCause = getDeepestCause(err);
49
+ if (rootCause !== err) {
50
+ const rootMsg = rootCause.message || String(rootCause);
51
+ if (err.message && !err.message.includes(rootMsg)) {
52
+ return `${err.message}: ${rootMsg}`;
53
+ }
54
+ }
55
+ return err.message;
56
+ }
57
+ function getDeepestCause(err) {
58
+ let current = err;
59
+ const seen = /* @__PURE__ */ new Set();
60
+ while (current.cause instanceof Error && !seen.has(current.cause)) {
61
+ seen.add(current);
62
+ current = current.cause;
63
+ }
64
+ return current;
65
+ }
66
+ function getErrorCode(err) {
67
+ if (!(err instanceof Error)) return void 0;
68
+ let current = err;
69
+ const seen = /* @__PURE__ */ new Set();
70
+ while (current && !seen.has(current)) {
71
+ seen.add(current);
72
+ const code = current.code;
73
+ if (typeof code === "string") return code;
74
+ current = current.cause instanceof Error ? current.cause : void 0;
75
+ }
76
+ return void 0;
48
77
  }
49
78
 
50
79
  // src/fetch.ts
@@ -101,10 +130,10 @@ var FileConfigStore = class {
101
130
  credentialsFile;
102
131
  sessionFile;
103
132
  constructor(configDir) {
104
- this.configDir = configDir ?? process.env.ARBI_CONFIG_DIR ?? path__default.default.join(os__default.default.homedir(), ".arbi");
105
- this.configFile = path__default.default.join(this.configDir, "config.json");
106
- this.credentialsFile = path__default.default.join(this.configDir, "credentials.json");
107
- this.sessionFile = path__default.default.join(this.configDir, "session.json");
133
+ this.configDir = configDir ?? process.env.ARBI_CONFIG_DIR ?? path2__default.default.join(os__default.default.homedir(), ".arbi");
134
+ this.configFile = path2__default.default.join(this.configDir, "config.json");
135
+ this.credentialsFile = path2__default.default.join(this.configDir, "credentials.json");
136
+ this.sessionFile = path2__default.default.join(this.configDir, "session.json");
108
137
  }
109
138
  ensureConfigDir() {
110
139
  if (!fs__default.default.existsSync(this.configDir)) {
@@ -175,6 +204,77 @@ var FileConfigStore = class {
175
204
  clearChatSession() {
176
205
  this.saveChatSession({ ...DEFAULT_SESSION });
177
206
  }
207
+ /**
208
+ * Try to resolve config from multiple sources, in priority order:
209
+ *
210
+ * 1. Existing `~/.arbi/config.json` (highest priority)
211
+ * 2. `ARBI_SERVER_URL` environment variable
212
+ * 3. `.env` file in `searchDir` → read `VITE_DEPLOYMENT_DOMAIN`
213
+ * 4. `public/config.json` in `searchDir` → read `deployment.domain`
214
+ * 5. Default to `https://localhost`
215
+ *
216
+ * Returns `{ config, source }` where source describes where the config came from.
217
+ * Saves auto-detected config to disk so subsequent calls use the fast path.
218
+ */
219
+ resolveConfigWithFallbacks(searchDir) {
220
+ const existing = this.getConfig();
221
+ if (existing?.baseUrl) {
222
+ return { config: existing, source: "config" };
223
+ }
224
+ const envUrl = process.env.ARBI_SERVER_URL;
225
+ if (envUrl) {
226
+ const domain = new URL(envUrl).hostname;
227
+ const config2 = { baseUrl: envUrl.replace(/\/$/, ""), deploymentDomain: domain };
228
+ this.saveConfig(config2);
229
+ return { config: config2, source: "ARBI_SERVER_URL env var" };
230
+ }
231
+ const dir = searchDir || process.cwd();
232
+ const dotenvConfig = this.readDotEnvDomain(path2__default.default.join(dir, ".env"));
233
+ if (dotenvConfig) {
234
+ this.saveConfig(dotenvConfig);
235
+ return { config: dotenvConfig, source: ".env file" };
236
+ }
237
+ const publicConfig = this.readPublicConfigDomain(path2__default.default.join(dir, "public", "config.json"));
238
+ if (publicConfig) {
239
+ this.saveConfig(publicConfig);
240
+ return { config: publicConfig, source: "public/config.json" };
241
+ }
242
+ const config = { baseUrl: "https://localhost", deploymentDomain: "localhost" };
243
+ this.saveConfig(config);
244
+ return { config, source: "default (https://localhost)" };
245
+ }
246
+ /**
247
+ * Read VITE_DEPLOYMENT_DOMAIN from a .env file.
248
+ */
249
+ readDotEnvDomain(filePath) {
250
+ try {
251
+ const content = fs__default.default.readFileSync(filePath, "utf-8");
252
+ const match = content.match(/^VITE_DEPLOYMENT_DOMAIN\s*=\s*(.+)$/m);
253
+ if (match) {
254
+ const domain = match[1].trim().replace(/^["']|["']$/g, "");
255
+ if (domain) {
256
+ return { baseUrl: `https://${domain}`, deploymentDomain: domain };
257
+ }
258
+ }
259
+ } catch {
260
+ }
261
+ return null;
262
+ }
263
+ /**
264
+ * Read deployment.domain from a public/config.json file.
265
+ */
266
+ readPublicConfigDomain(filePath) {
267
+ try {
268
+ const content = fs__default.default.readFileSync(filePath, "utf-8");
269
+ const json = JSON.parse(content);
270
+ const domain = json?.deployment?.domain;
271
+ if (domain) {
272
+ return { baseUrl: `https://${domain}`, deploymentDomain: domain };
273
+ }
274
+ } catch {
275
+ }
276
+ return null;
277
+ }
178
278
  };
179
279
  function formatWorkspaceChoices(wsList) {
180
280
  return wsList.map((ws) => {
@@ -200,7 +300,11 @@ async function createAuthenticatedClient(config, creds, store) {
200
300
  });
201
301
  store.saveCredentials({
202
302
  ...creds,
203
- serverSessionKeyBase64: arbi.crypto.bytesToBase64(loginResult.serverSessionKey)
303
+ serverSessionKeyBase64: arbi.crypto.bytesToBase64(loginResult.serverSessionKey),
304
+ accessToken: void 0,
305
+ workspaceKeyHeader: void 0,
306
+ workspaceId: void 0,
307
+ tokenTimestamp: void 0
204
308
  });
205
309
  return { arbi, loginResult };
206
310
  }
@@ -215,7 +319,12 @@ async function performPasswordLogin(config, email, password, store) {
215
319
  store.saveCredentials({
216
320
  email,
217
321
  signingPrivateKeyBase64: arbi.crypto.bytesToBase64(loginResult.signingPrivateKey),
218
- serverSessionKeyBase64: arbi.crypto.bytesToBase64(loginResult.serverSessionKey)
322
+ serverSessionKeyBase64: arbi.crypto.bytesToBase64(loginResult.serverSessionKey),
323
+ // Clear any cached workspace tokens — new session key invalidates them
324
+ accessToken: void 0,
325
+ workspaceKeyHeader: void 0,
326
+ workspaceId: void 0,
327
+ tokenTimestamp: void 0
219
328
  });
220
329
  return { arbi, loginResult, config };
221
330
  }
@@ -278,6 +387,10 @@ async function resolveAuth(store) {
278
387
  const { arbi, loginResult } = await createAuthenticatedClient(config, creds, store);
279
388
  return { arbi, loginResult, config };
280
389
  }
390
+ var TOKEN_MAX_AGE_MS = 50 * 60 * 1e3;
391
+ function isCachedTokenValid(creds, workspaceId) {
392
+ return !!(creds.accessToken && creds.workspaceKeyHeader && creds.workspaceId === workspaceId && creds.tokenTimestamp && Date.now() - new Date(creds.tokenTimestamp).getTime() < TOKEN_MAX_AGE_MS);
393
+ }
281
394
  async function resolveWorkspace(store, workspaceOpt) {
282
395
  const config = store.requireConfig();
283
396
  const creds = store.requireCredentials();
@@ -285,6 +398,32 @@ async function resolveWorkspace(store, workspaceOpt) {
285
398
  if (!workspaceId) {
286
399
  throw new ArbiError("No workspace selected. Run: arbi workspace select <id>");
287
400
  }
401
+ if (isCachedTokenValid(creds, workspaceId)) {
402
+ const arbi2 = client.createArbiClient({
403
+ baseUrl: config.baseUrl,
404
+ deploymentDomain: config.deploymentDomain,
405
+ credentials: "omit"
406
+ });
407
+ await arbi2.crypto.initSodium();
408
+ arbi2.session.setSelectedWorkspace(workspaceId);
409
+ arbi2.session.setAccessToken(creds.accessToken);
410
+ arbi2.session.setCachedWorkspaceHeader(workspaceId, creds.workspaceKeyHeader);
411
+ const signingPrivateKey = client.base64ToBytes(creds.signingPrivateKeyBase64);
412
+ const serverSessionKey = client.base64ToBytes(creds.serverSessionKeyBase64);
413
+ const loginResult2 = {
414
+ accessToken: creds.accessToken,
415
+ signingPrivateKey,
416
+ serverSessionKey
417
+ };
418
+ return {
419
+ arbi: arbi2,
420
+ loginResult: loginResult2,
421
+ config,
422
+ workspaceId,
423
+ accessToken: creds.accessToken,
424
+ workspaceKeyHeader: creds.workspaceKeyHeader
425
+ };
426
+ }
288
427
  const { arbi, loginResult } = await createAuthenticatedClient(config, creds, store);
289
428
  await selectWorkspaceById(
290
429
  arbi,
@@ -297,10 +436,57 @@ async function resolveWorkspace(store, workspaceOpt) {
297
436
  if (!accessToken || !workspaceKeyHeader) {
298
437
  throw new ArbiError("Authentication error \u2014 missing token or workspace key");
299
438
  }
439
+ store.saveCredentials({
440
+ ...store.requireCredentials(),
441
+ accessToken,
442
+ workspaceKeyHeader,
443
+ workspaceId,
444
+ tokenTimestamp: (/* @__PURE__ */ new Date()).toISOString()
445
+ });
300
446
  return { arbi, loginResult, config, workspaceId, accessToken, workspaceKeyHeader };
301
447
  }
302
448
 
303
449
  // src/sse.ts
450
+ var TOOL_LABELS = {
451
+ search_documents: "Searching documents",
452
+ get_document_passages: "Reading document",
453
+ get_table_of_contents: "Getting table of contents",
454
+ view_document_pages: "Viewing document pages",
455
+ get_full_document: "Reading full document",
456
+ web_search: "Searching the web",
457
+ read_url: "Reading web pages",
458
+ ask_user: "Asking user",
459
+ compaction: "Compacting conversation",
460
+ personal_agent: "Running agent",
461
+ create_artifact: "Creating artifact",
462
+ create_plan: "Creating plan",
463
+ save_skill: "Saving skill",
464
+ run_code: "Running code"
465
+ };
466
+ var LIFECYCLE_LABELS = {
467
+ evaluation: "Evaluating results",
468
+ answering: "Writing answer",
469
+ reviewing: "Reviewing answer",
470
+ planning: "Planning",
471
+ tool_progress: "Working"
472
+ };
473
+ function formatAgentStepLabel(step) {
474
+ if (step.focus) return step.focus;
475
+ const detail = step.detail;
476
+ if (step.step === "tool_progress" && detail && detail.length > 0) {
477
+ const toolName = detail[0].tool;
478
+ const label = toolName && TOOL_LABELS[toolName] || LIFECYCLE_LABELS.tool_progress;
479
+ const message = detail[0].message;
480
+ return message ? `${label}: ${message}` : label;
481
+ }
482
+ if (step.step) {
483
+ return LIFECYCLE_LABELS[step.step] || step.step;
484
+ }
485
+ if (detail && detail.length > 0 && detail[0].tool) {
486
+ return TOOL_LABELS[detail[0].tool] || detail[0].tool;
487
+ }
488
+ return "";
489
+ }
304
490
  function parseSSEEvents(chunk, buffer) {
305
491
  const combined = buffer + chunk;
306
492
  const events = [];
@@ -328,11 +514,13 @@ async function streamSSE(response, callbacks = {}) {
328
514
  let text = "";
329
515
  let assistantMessageExtId = null;
330
516
  const agentSteps = [];
517
+ let toolCallCount = 0;
331
518
  const errors = [];
332
519
  const artifacts = [];
333
520
  let userMessage = null;
334
521
  let metadata = null;
335
522
  let usage = null;
523
+ let context = null;
336
524
  const eventHandlers = {
337
525
  // OpenAI Responses API events (dot-separated names from server)
338
526
  "response.created": (raw) => {
@@ -376,6 +564,9 @@ async function streamSSE(response, callbacks = {}) {
376
564
  metadata = meta;
377
565
  callbacks.onMetadata?.(meta);
378
566
  }
567
+ if (data.context) {
568
+ context = data.context;
569
+ }
379
570
  if (data.t != null) callbacks.onElapsedTime?.(data.t);
380
571
  callbacks.onComplete?.();
381
572
  },
@@ -388,8 +579,12 @@ async function streamSSE(response, callbacks = {}) {
388
579
  // ARBI-specific events (dot-prefixed from server)
389
580
  "arbi.agent_step": (raw) => {
390
581
  const data = JSON.parse(raw);
391
- const focus = data.focus || data.step || "";
392
- if (focus) agentSteps.push(focus);
582
+ const label = formatAgentStepLabel(data);
583
+ if (label) agentSteps.push(label);
584
+ const detail = data.detail;
585
+ if (detail && Array.isArray(detail)) {
586
+ toolCallCount += detail.filter((d) => d.tool).length;
587
+ }
393
588
  callbacks.onAgentStep?.(data);
394
589
  if (data.t != null) callbacks.onElapsedTime?.(data.t);
395
590
  },
@@ -440,11 +635,13 @@ async function streamSSE(response, callbacks = {}) {
440
635
  text,
441
636
  assistantMessageExtId,
442
637
  agentSteps,
638
+ toolCallCount,
443
639
  errors,
444
640
  userMessage,
445
641
  metadata,
446
642
  artifacts,
447
- usage
643
+ usage,
644
+ context
448
645
  };
449
646
  }
450
647
  var consumeSSEStream = streamSSE;
@@ -643,6 +840,13 @@ function formatWsMessage(msg) {
643
840
  if (client.isMessageType(msg, "presence_update")) {
644
841
  return { text: `${msg.user_id} is ${msg.status}`, level: "info" };
645
842
  }
843
+ if (client.isMessageType(msg, "response_complete")) {
844
+ const icon = msg.status === "completed" ? "\u2713" : "\u2717";
845
+ return {
846
+ text: `${icon} Task ${msg.response_id} ${msg.status}`,
847
+ level: msg.status === "completed" ? "success" : "error"
848
+ };
849
+ }
646
850
  if (isNotification(msg)) {
647
851
  const sender = msg.sender?.email || "someone";
648
852
  const content = msg.content ?? msg.type;
@@ -667,16 +871,34 @@ function formatUserName(user) {
667
871
  // src/operations/documents.ts
668
872
  var documents_exports = {};
669
873
  __export(documents_exports, {
874
+ SUPPORTED_EXTENSIONS: () => SUPPORTED_EXTENSIONS,
670
875
  deleteDocuments: () => deleteDocuments,
671
876
  downloadDocument: () => downloadDocument,
672
877
  getDocuments: () => getDocuments,
673
878
  getParsedContent: () => getParsedContent,
674
879
  listDocuments: () => listDocuments,
880
+ sanitizeFolderPath: () => sanitizeFolderPath,
675
881
  updateDocuments: () => updateDocuments,
676
882
  uploadFile: () => uploadFile,
677
- uploadLocalFile: () => uploadLocalFile,
883
+ uploadFiles: () => uploadFiles,
678
884
  uploadUrl: () => uploadUrl
679
885
  });
886
+ var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([
887
+ ".pdf",
888
+ ".txt",
889
+ ".md",
890
+ ".html",
891
+ ".doc",
892
+ ".docx",
893
+ ".rtf",
894
+ ".ppt",
895
+ ".pptx",
896
+ ".xls",
897
+ ".xlsx"
898
+ ]);
899
+ function sanitizeFolderPath(folderPath) {
900
+ return folderPath.replace(/[^a-zA-Z0-9_\-/]/g, "_").replace(/_{2,}/g, "_");
901
+ }
680
902
  async function listDocuments(arbi) {
681
903
  return requireData(await arbi.fetch.GET("/v1/document/list"), "Failed to fetch documents");
682
904
  }
@@ -715,22 +937,31 @@ async function getParsedContent(auth, docId, stage) {
715
937
  });
716
938
  return res.json();
717
939
  }
718
- async function uploadFile(auth, workspaceId, fileData, fileName) {
940
+ async function uploadFile(auth, workspaceId, fileData, fileName, options) {
719
941
  const formData = new FormData();
720
942
  formData.append("files", fileData, fileName);
943
+ const params = new URLSearchParams({ workspace_ext_id: workspaceId });
944
+ if (options?.folder) params.set("folder", sanitizeFolderPath(options.folder));
721
945
  const res = await authenticatedFetch({
722
946
  ...auth,
723
- path: `/v1/document/upload?workspace_ext_id=${workspaceId}`,
947
+ path: `/v1/document/upload?${params.toString()}`,
724
948
  method: "POST",
725
949
  body: formData
726
950
  });
727
951
  return res.json();
728
952
  }
729
- async function uploadLocalFile(auth, workspaceId, filePath) {
730
- const fileBuffer = fs__default.default.readFileSync(filePath);
731
- const fileName = path__default.default.basename(filePath);
732
- const result = await uploadFile(auth, workspaceId, new Blob([fileBuffer]), fileName);
733
- return { ...result, fileName };
953
+ async function uploadFiles(auth, workspaceId, files, options) {
954
+ const formData = new FormData();
955
+ for (const f of files) formData.append("files", f.data, f.name);
956
+ const params = new URLSearchParams({ workspace_ext_id: workspaceId });
957
+ if (options?.folder) params.set("folder", sanitizeFolderPath(options.folder));
958
+ const res = await authenticatedFetch({
959
+ ...auth,
960
+ path: `/v1/document/upload?${params.toString()}`,
961
+ method: "POST",
962
+ body: formData
963
+ });
964
+ return res.json();
734
965
  }
735
966
  async function downloadDocument(auth, docId) {
736
967
  return authenticatedFetch({
@@ -930,6 +1161,8 @@ async function retrieve(options) {
930
1161
  input: query,
931
1162
  workspace_ext_id: workspaceId,
932
1163
  stream: false,
1164
+ background: false,
1165
+ store: true,
933
1166
  tools,
934
1167
  ...model ? { model } : {}
935
1168
  };
@@ -945,6 +1178,8 @@ async function queryAssistant(options) {
945
1178
  input: question,
946
1179
  workspace_ext_id: workspaceId,
947
1180
  stream: true,
1181
+ background: false,
1182
+ store: true,
948
1183
  tools: {
949
1184
  retrieval_chunk: buildRetrievalChunkTool(docIds),
950
1185
  retrieval_full_context: buildRetrievalFullContextTool([])
@@ -1404,11 +1639,12 @@ var Arbi = class {
1404
1639
  workspaceId ?? this.requireWorkspace(),
1405
1640
  shared
1406
1641
  ),
1407
- uploadFile: (fileData, fileName, workspaceId) => uploadFile(
1642
+ uploadFile: (fileData, fileName, options) => uploadFile(
1408
1643
  this.getAuthHeaders(),
1409
- workspaceId ?? this.requireWorkspace(),
1644
+ options?.workspaceId ?? this.requireWorkspace(),
1410
1645
  fileData,
1411
- fileName
1646
+ fileName,
1647
+ options?.folder ? { folder: options.folder } : void 0
1412
1648
  ),
1413
1649
  download: (docId) => downloadDocument(this.getAuthHeaders(), docId),
1414
1650
  getParsedContent: (docId, stage) => getParsedContent(this.getAuthHeaders(), docId, stage)
@@ -1550,10 +1786,192 @@ var Arbi = class {
1550
1786
  }
1551
1787
  };
1552
1788
 
1789
+ // src/operations/documents-node.ts
1790
+ var documents_node_exports = {};
1791
+ __export(documents_node_exports, {
1792
+ uploadDirectory: () => uploadDirectory,
1793
+ uploadLocalFile: () => uploadLocalFile,
1794
+ uploadZip: () => uploadZip
1795
+ });
1796
+ function collectFiles(dirPath, baseDir) {
1797
+ const root = baseDir ?? dirPath;
1798
+ const results = [];
1799
+ for (const entry of fs__default.default.readdirSync(dirPath, { withFileTypes: true })) {
1800
+ const fullPath = path2__default.default.join(dirPath, entry.name);
1801
+ if (entry.isDirectory()) {
1802
+ results.push(...collectFiles(fullPath, root));
1803
+ } else if (entry.isFile()) {
1804
+ const ext = path2__default.default.extname(entry.name).toLowerCase();
1805
+ if (SUPPORTED_EXTENSIONS.has(ext)) {
1806
+ results.push({ absolutePath: fullPath, relativePath: path2__default.default.relative(root, fullPath) });
1807
+ }
1808
+ }
1809
+ }
1810
+ return results;
1811
+ }
1812
+ async function uploadLocalFile(auth, workspaceId, filePath, options) {
1813
+ const fileBuffer = fs__default.default.readFileSync(filePath);
1814
+ const fileName = path2__default.default.basename(filePath);
1815
+ const result = await uploadFile(auth, workspaceId, new Blob([fileBuffer]), fileName, options);
1816
+ return { ...result, fileName };
1817
+ }
1818
+ async function uploadDirectory(auth, workspaceId, dirPath) {
1819
+ const resolvedDir = path2__default.default.resolve(dirPath);
1820
+ const dirName = path2__default.default.basename(resolvedDir);
1821
+ const entries = collectFiles(resolvedDir);
1822
+ if (entries.length === 0) {
1823
+ return { doc_ext_ids: [], duplicates: [], folders: /* @__PURE__ */ new Map() };
1824
+ }
1825
+ const groups = /* @__PURE__ */ new Map();
1826
+ for (const entry of entries) {
1827
+ const relDir = path2__default.default.dirname(entry.relativePath);
1828
+ const folder = relDir === "." ? dirName : `${dirName}/${relDir}`;
1829
+ if (!groups.has(folder)) groups.set(folder, []);
1830
+ groups.get(folder).push({ absolutePath: entry.absolutePath, name: path2__default.default.basename(entry.relativePath) });
1831
+ }
1832
+ const allDocIds = [];
1833
+ const allDuplicates = [];
1834
+ const folders = /* @__PURE__ */ new Map();
1835
+ for (const [folder, files] of groups) {
1836
+ const blobs = files.map((f) => ({
1837
+ data: new Blob([fs__default.default.readFileSync(f.absolutePath)]),
1838
+ name: f.name
1839
+ }));
1840
+ const result = await uploadFiles(auth, workspaceId, blobs, { folder });
1841
+ const dups = result.duplicates ?? [];
1842
+ allDocIds.push(...result.doc_ext_ids);
1843
+ allDuplicates.push(...dups);
1844
+ folders.set(folder, {
1845
+ fileCount: files.length,
1846
+ doc_ext_ids: result.doc_ext_ids,
1847
+ duplicates: dups
1848
+ });
1849
+ }
1850
+ return { doc_ext_ids: allDocIds, duplicates: allDuplicates, folders };
1851
+ }
1852
+ async function uploadZip(auth, workspaceId, zipPath) {
1853
+ const JSZip = (await import('jszip')).default;
1854
+ const zipBuffer = fs__default.default.readFileSync(zipPath);
1855
+ const zip = await JSZip.loadAsync(zipBuffer);
1856
+ const zipBaseName = path2__default.default.basename(zipPath).replace(/\.zip$/i, "");
1857
+ const entries = [];
1858
+ zip.forEach((relativePath, zipEntry) => {
1859
+ if (zipEntry.dir) return;
1860
+ const ext = path2__default.default.extname(relativePath).toLowerCase();
1861
+ if (SUPPORTED_EXTENSIONS.has(ext)) {
1862
+ entries.push({ zipEntryPath: relativePath, zipEntry });
1863
+ }
1864
+ });
1865
+ if (entries.length === 0) {
1866
+ return { doc_ext_ids: [], duplicates: [], folders: /* @__PURE__ */ new Map() };
1867
+ }
1868
+ const firstParts = new Set(entries.map((e) => e.zipEntryPath.split("/")[0]));
1869
+ const hasSingleRoot = firstParts.size === 1 && entries.every((e) => e.zipEntryPath.includes("/"));
1870
+ const groups = /* @__PURE__ */ new Map();
1871
+ for (const entry of entries) {
1872
+ const data = await entry.zipEntry.async("uint8array");
1873
+ const fileName = path2__default.default.basename(entry.zipEntryPath);
1874
+ const relDir = path2__default.default.dirname(entry.zipEntryPath);
1875
+ let folder;
1876
+ if (hasSingleRoot) {
1877
+ folder = relDir === "." ? zipBaseName : relDir;
1878
+ } else {
1879
+ folder = relDir === "." ? zipBaseName : `${zipBaseName}/${relDir}`;
1880
+ }
1881
+ folder = sanitizeFolderPath(folder);
1882
+ if (!groups.has(folder)) groups.set(folder, []);
1883
+ groups.get(folder).push({ name: fileName, data });
1884
+ }
1885
+ const allDocIds = [];
1886
+ const allDuplicates = [];
1887
+ const folders = /* @__PURE__ */ new Map();
1888
+ for (const [folder, files] of groups) {
1889
+ const blobs = files.map((f) => ({
1890
+ data: new Blob([f.data]),
1891
+ name: f.name
1892
+ }));
1893
+ const result = await uploadFiles(auth, workspaceId, blobs, { folder });
1894
+ const dups = result.duplicates ?? [];
1895
+ allDocIds.push(...result.doc_ext_ids);
1896
+ allDuplicates.push(...dups);
1897
+ folders.set(folder, {
1898
+ fileCount: files.length,
1899
+ doc_ext_ids: result.doc_ext_ids,
1900
+ duplicates: dups
1901
+ });
1902
+ }
1903
+ return { doc_ext_ids: allDocIds, duplicates: allDuplicates, folders };
1904
+ }
1905
+
1906
+ // src/operations/responses.ts
1907
+ var responses_exports = {};
1908
+ __export(responses_exports, {
1909
+ extractResponseText: () => extractResponseText,
1910
+ getResponse: () => getResponse,
1911
+ submitBackgroundQuery: () => submitBackgroundQuery
1912
+ });
1913
+ async function submitBackgroundQuery(options) {
1914
+ const { workspaceId, question, docIds, previousResponseId, model, ...auth } = options;
1915
+ const tools = {};
1916
+ if (docIds.length > 0) {
1917
+ tools.retrieval_chunk = {
1918
+ name: "retrieval_chunk",
1919
+ description: "retrieval chunk",
1920
+ tool_args: { doc_ext_ids: docIds },
1921
+ tool_responses: {}
1922
+ };
1923
+ tools.retrieval_full_context = {
1924
+ name: "retrieval_full_context",
1925
+ description: "retrieval full context",
1926
+ tool_args: { doc_ext_ids: [] },
1927
+ tool_responses: {}
1928
+ };
1929
+ }
1930
+ const body = {
1931
+ input: question,
1932
+ workspace_ext_id: workspaceId,
1933
+ stream: false,
1934
+ background: true,
1935
+ store: true,
1936
+ tools,
1937
+ ...previousResponseId ? { previous_response_id: previousResponseId } : {},
1938
+ ...model ? { model } : {}
1939
+ };
1940
+ const res = await authenticatedFetch({
1941
+ ...auth,
1942
+ path: "/v1/responses",
1943
+ method: "POST",
1944
+ body: JSON.stringify(body),
1945
+ headers: { "Content-Type": "application/json" }
1946
+ });
1947
+ return await res.json();
1948
+ }
1949
+ async function getResponse(auth, responseId) {
1950
+ const res = await authenticatedFetch({
1951
+ ...auth,
1952
+ path: `/v1/responses/${responseId}`,
1953
+ method: "GET"
1954
+ });
1955
+ return await res.json();
1956
+ }
1957
+ function extractResponseText(response) {
1958
+ const parts = [];
1959
+ for (const msg of response.output) {
1960
+ for (const item of msg.content) {
1961
+ if ("type" in item && item.type === "output_text" && "text" in item) {
1962
+ parts.push(item.text);
1963
+ }
1964
+ }
1965
+ }
1966
+ return parts.join("");
1967
+ }
1968
+
1553
1969
  exports.Arbi = Arbi;
1554
1970
  exports.ArbiApiError = ArbiApiError;
1555
1971
  exports.ArbiError = ArbiError;
1556
1972
  exports.FileConfigStore = FileConfigStore;
1973
+ exports.LIFECYCLE_LABELS = LIFECYCLE_LABELS;
1974
+ exports.TOOL_LABELS = TOOL_LABELS;
1557
1975
  exports.agentconfig = agentconfig_exports;
1558
1976
  exports.assistant = assistant_exports;
1559
1977
  exports.authenticatedFetch = authenticatedFetch;
@@ -1570,12 +1988,15 @@ exports.createDocumentWaiter = createDocumentWaiter;
1570
1988
  exports.dm = dm_exports;
1571
1989
  exports.doctags = doctags_exports;
1572
1990
  exports.documents = documents_exports;
1991
+ exports.documentsNode = documents_node_exports;
1573
1992
  exports.files = files_exports;
1993
+ exports.formatAgentStepLabel = formatAgentStepLabel;
1574
1994
  exports.formatFileSize = formatFileSize;
1575
1995
  exports.formatUserName = formatUserName;
1576
1996
  exports.formatWorkspaceChoices = formatWorkspaceChoices;
1577
1997
  exports.formatWsMessage = formatWsMessage;
1578
1998
  exports.generateEncryptedWorkspaceKey = generateEncryptedWorkspaceKey;
1999
+ exports.getErrorCode = getErrorCode;
1579
2000
  exports.getErrorMessage = getErrorMessage;
1580
2001
  exports.health = health_exports;
1581
2002
  exports.parseSSEEvents = parseSSEEvents;
@@ -1584,6 +2005,7 @@ exports.requireData = requireData;
1584
2005
  exports.requireOk = requireOk;
1585
2006
  exports.resolveAuth = resolveAuth;
1586
2007
  exports.resolveWorkspace = resolveWorkspace;
2008
+ exports.responses = responses_exports;
1587
2009
  exports.selectWorkspace = selectWorkspace;
1588
2010
  exports.selectWorkspaceById = selectWorkspaceById;
1589
2011
  exports.settings = settings_exports;