@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/browser.cjs CHANGED
@@ -1,13 +1,6 @@
1
1
  'use strict';
2
2
 
3
3
  var client = require('@arbidocs/client');
4
- var fs = require('fs');
5
- var path = require('path');
6
-
7
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
-
9
- var fs__default = /*#__PURE__*/_interopDefault(fs);
10
- var path__default = /*#__PURE__*/_interopDefault(path);
11
4
 
12
5
  var __defProp = Object.defineProperty;
13
6
  var __export = (target, all) => {
@@ -42,7 +35,24 @@ function requireOk(result, message) {
42
35
  }
43
36
  }
44
37
  function getErrorMessage(err) {
45
- return err instanceof Error ? err.message : String(err);
38
+ if (!(err instanceof Error)) return String(err);
39
+ const rootCause = getDeepestCause(err);
40
+ if (rootCause !== err) {
41
+ const rootMsg = rootCause.message || String(rootCause);
42
+ if (err.message && !err.message.includes(rootMsg)) {
43
+ return `${err.message}: ${rootMsg}`;
44
+ }
45
+ }
46
+ return err.message;
47
+ }
48
+ function getDeepestCause(err) {
49
+ let current = err;
50
+ const seen = /* @__PURE__ */ new Set();
51
+ while (current.cause instanceof Error && !seen.has(current.cause)) {
52
+ seen.add(current);
53
+ current = current.cause;
54
+ }
55
+ return current;
46
56
  }
47
57
 
48
58
  // src/fetch.ts
@@ -72,8 +82,8 @@ async function extractErrorMessage(res) {
72
82
  return `Request failed: ${res.status} ${res.statusText}`;
73
83
  }
74
84
  async function authenticatedFetch(options) {
75
- const { baseUrl, accessToken, workspaceKeyHeader, path: path2, method, body, headers } = options;
76
- const res = await fetch(`${baseUrl}${path2}`, {
85
+ const { baseUrl, accessToken, workspaceKeyHeader, path, method, body, headers } = options;
86
+ const res = await fetch(`${baseUrl}${path}`, {
77
87
  method: method ?? (body ? "POST" : "GET"),
78
88
  headers: {
79
89
  Authorization: `Bearer ${accessToken}`,
@@ -112,7 +122,11 @@ async function createAuthenticatedClient(config, creds, store) {
112
122
  });
113
123
  store.saveCredentials({
114
124
  ...creds,
115
- serverSessionKeyBase64: arbi.crypto.bytesToBase64(loginResult.serverSessionKey)
125
+ serverSessionKeyBase64: arbi.crypto.bytesToBase64(loginResult.serverSessionKey),
126
+ accessToken: void 0,
127
+ workspaceKeyHeader: void 0,
128
+ workspaceId: void 0,
129
+ tokenTimestamp: void 0
116
130
  });
117
131
  return { arbi, loginResult };
118
132
  }
@@ -127,7 +141,12 @@ async function performPasswordLogin(config, email, password, store) {
127
141
  store.saveCredentials({
128
142
  email,
129
143
  signingPrivateKeyBase64: arbi.crypto.bytesToBase64(loginResult.signingPrivateKey),
130
- serverSessionKeyBase64: arbi.crypto.bytesToBase64(loginResult.serverSessionKey)
144
+ serverSessionKeyBase64: arbi.crypto.bytesToBase64(loginResult.serverSessionKey),
145
+ // Clear any cached workspace tokens — new session key invalidates them
146
+ accessToken: void 0,
147
+ workspaceKeyHeader: void 0,
148
+ workspaceId: void 0,
149
+ tokenTimestamp: void 0
131
150
  });
132
151
  return { arbi, loginResult, config };
133
152
  }
@@ -180,6 +199,10 @@ async function resolveAuth(store) {
180
199
  const { arbi, loginResult } = await createAuthenticatedClient(config, creds, store);
181
200
  return { arbi, loginResult, config };
182
201
  }
202
+ var TOKEN_MAX_AGE_MS = 50 * 60 * 1e3;
203
+ function isCachedTokenValid(creds, workspaceId) {
204
+ return !!(creds.accessToken && creds.workspaceKeyHeader && creds.workspaceId === workspaceId && creds.tokenTimestamp && Date.now() - new Date(creds.tokenTimestamp).getTime() < TOKEN_MAX_AGE_MS);
205
+ }
183
206
  async function resolveWorkspace(store, workspaceOpt) {
184
207
  const config = store.requireConfig();
185
208
  const creds = store.requireCredentials();
@@ -187,6 +210,32 @@ async function resolveWorkspace(store, workspaceOpt) {
187
210
  if (!workspaceId) {
188
211
  throw new ArbiError("No workspace selected. Run: arbi workspace select <id>");
189
212
  }
213
+ if (isCachedTokenValid(creds, workspaceId)) {
214
+ const arbi2 = client.createArbiClient({
215
+ baseUrl: config.baseUrl,
216
+ deploymentDomain: config.deploymentDomain,
217
+ credentials: "omit"
218
+ });
219
+ await arbi2.crypto.initSodium();
220
+ arbi2.session.setSelectedWorkspace(workspaceId);
221
+ arbi2.session.setAccessToken(creds.accessToken);
222
+ arbi2.session.setCachedWorkspaceHeader(workspaceId, creds.workspaceKeyHeader);
223
+ const signingPrivateKey = client.base64ToBytes(creds.signingPrivateKeyBase64);
224
+ const serverSessionKey = client.base64ToBytes(creds.serverSessionKeyBase64);
225
+ const loginResult2 = {
226
+ accessToken: creds.accessToken,
227
+ signingPrivateKey,
228
+ serverSessionKey
229
+ };
230
+ return {
231
+ arbi: arbi2,
232
+ loginResult: loginResult2,
233
+ config,
234
+ workspaceId,
235
+ accessToken: creds.accessToken,
236
+ workspaceKeyHeader: creds.workspaceKeyHeader
237
+ };
238
+ }
190
239
  const { arbi, loginResult } = await createAuthenticatedClient(config, creds, store);
191
240
  await selectWorkspaceById(
192
241
  arbi,
@@ -199,10 +248,57 @@ async function resolveWorkspace(store, workspaceOpt) {
199
248
  if (!accessToken || !workspaceKeyHeader) {
200
249
  throw new ArbiError("Authentication error \u2014 missing token or workspace key");
201
250
  }
251
+ store.saveCredentials({
252
+ ...store.requireCredentials(),
253
+ accessToken,
254
+ workspaceKeyHeader,
255
+ workspaceId,
256
+ tokenTimestamp: (/* @__PURE__ */ new Date()).toISOString()
257
+ });
202
258
  return { arbi, loginResult, config, workspaceId, accessToken, workspaceKeyHeader };
203
259
  }
204
260
 
205
261
  // src/sse.ts
262
+ var TOOL_LABELS = {
263
+ search_documents: "Searching documents",
264
+ get_document_passages: "Reading document",
265
+ get_table_of_contents: "Getting table of contents",
266
+ view_document_pages: "Viewing document pages",
267
+ get_full_document: "Reading full document",
268
+ web_search: "Searching the web",
269
+ read_url: "Reading web pages",
270
+ ask_user: "Asking user",
271
+ compaction: "Compacting conversation",
272
+ personal_agent: "Running agent",
273
+ create_artifact: "Creating artifact",
274
+ create_plan: "Creating plan",
275
+ save_skill: "Saving skill",
276
+ run_code: "Running code"
277
+ };
278
+ var LIFECYCLE_LABELS = {
279
+ evaluation: "Evaluating results",
280
+ answering: "Writing answer",
281
+ reviewing: "Reviewing answer",
282
+ planning: "Planning",
283
+ tool_progress: "Working"
284
+ };
285
+ function formatAgentStepLabel(step) {
286
+ if (step.focus) return step.focus;
287
+ const detail = step.detail;
288
+ if (step.step === "tool_progress" && detail && detail.length > 0) {
289
+ const toolName = detail[0].tool;
290
+ const label = toolName && TOOL_LABELS[toolName] || LIFECYCLE_LABELS.tool_progress;
291
+ const message = detail[0].message;
292
+ return message ? `${label}: ${message}` : label;
293
+ }
294
+ if (step.step) {
295
+ return LIFECYCLE_LABELS[step.step] || step.step;
296
+ }
297
+ if (detail && detail.length > 0 && detail[0].tool) {
298
+ return TOOL_LABELS[detail[0].tool] || detail[0].tool;
299
+ }
300
+ return "";
301
+ }
206
302
  function parseSSEEvents(chunk, buffer) {
207
303
  const combined = buffer + chunk;
208
304
  const events = [];
@@ -230,11 +326,13 @@ async function streamSSE(response, callbacks = {}) {
230
326
  let text = "";
231
327
  let assistantMessageExtId = null;
232
328
  const agentSteps = [];
329
+ let toolCallCount = 0;
233
330
  const errors = [];
234
331
  const artifacts = [];
235
332
  let userMessage = null;
236
333
  let metadata = null;
237
334
  let usage = null;
335
+ let context = null;
238
336
  const eventHandlers = {
239
337
  // OpenAI Responses API events (dot-separated names from server)
240
338
  "response.created": (raw) => {
@@ -278,6 +376,9 @@ async function streamSSE(response, callbacks = {}) {
278
376
  metadata = meta;
279
377
  callbacks.onMetadata?.(meta);
280
378
  }
379
+ if (data.context) {
380
+ context = data.context;
381
+ }
281
382
  if (data.t != null) callbacks.onElapsedTime?.(data.t);
282
383
  callbacks.onComplete?.();
283
384
  },
@@ -290,8 +391,12 @@ async function streamSSE(response, callbacks = {}) {
290
391
  // ARBI-specific events (dot-prefixed from server)
291
392
  "arbi.agent_step": (raw) => {
292
393
  const data = JSON.parse(raw);
293
- const focus = data.focus || data.step || "";
294
- if (focus) agentSteps.push(focus);
394
+ const label = formatAgentStepLabel(data);
395
+ if (label) agentSteps.push(label);
396
+ const detail = data.detail;
397
+ if (detail && Array.isArray(detail)) {
398
+ toolCallCount += detail.filter((d) => d.tool).length;
399
+ }
295
400
  callbacks.onAgentStep?.(data);
296
401
  if (data.t != null) callbacks.onElapsedTime?.(data.t);
297
402
  },
@@ -342,11 +447,13 @@ async function streamSSE(response, callbacks = {}) {
342
447
  text,
343
448
  assistantMessageExtId,
344
449
  agentSteps,
450
+ toolCallCount,
345
451
  errors,
346
452
  userMessage,
347
453
  metadata,
348
454
  artifacts,
349
- usage
455
+ usage,
456
+ context
350
457
  };
351
458
  }
352
459
  var consumeSSEStream = streamSSE;
@@ -470,16 +577,34 @@ function formatUserName(user) {
470
577
  // src/operations/documents.ts
471
578
  var documents_exports = {};
472
579
  __export(documents_exports, {
580
+ SUPPORTED_EXTENSIONS: () => SUPPORTED_EXTENSIONS,
473
581
  deleteDocuments: () => deleteDocuments,
474
582
  downloadDocument: () => downloadDocument,
475
583
  getDocuments: () => getDocuments,
476
584
  getParsedContent: () => getParsedContent,
477
585
  listDocuments: () => listDocuments,
586
+ sanitizeFolderPath: () => sanitizeFolderPath,
478
587
  updateDocuments: () => updateDocuments,
479
588
  uploadFile: () => uploadFile,
480
- uploadLocalFile: () => uploadLocalFile,
589
+ uploadFiles: () => uploadFiles,
481
590
  uploadUrl: () => uploadUrl
482
591
  });
592
+ var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([
593
+ ".pdf",
594
+ ".txt",
595
+ ".md",
596
+ ".html",
597
+ ".doc",
598
+ ".docx",
599
+ ".rtf",
600
+ ".ppt",
601
+ ".pptx",
602
+ ".xls",
603
+ ".xlsx"
604
+ ]);
605
+ function sanitizeFolderPath(folderPath) {
606
+ return folderPath.replace(/[^a-zA-Z0-9_\-/]/g, "_").replace(/_{2,}/g, "_");
607
+ }
483
608
  async function listDocuments(arbi) {
484
609
  return requireData(await arbi.fetch.GET("/v1/document/list"), "Failed to fetch documents");
485
610
  }
@@ -518,22 +643,31 @@ async function getParsedContent(auth, docId, stage) {
518
643
  });
519
644
  return res.json();
520
645
  }
521
- async function uploadFile(auth, workspaceId, fileData, fileName) {
646
+ async function uploadFile(auth, workspaceId, fileData, fileName, options) {
522
647
  const formData = new FormData();
523
648
  formData.append("files", fileData, fileName);
649
+ const params = new URLSearchParams({ workspace_ext_id: workspaceId });
650
+ if (options?.folder) params.set("folder", sanitizeFolderPath(options.folder));
524
651
  const res = await authenticatedFetch({
525
652
  ...auth,
526
- path: `/v1/document/upload?workspace_ext_id=${workspaceId}`,
653
+ path: `/v1/document/upload?${params.toString()}`,
527
654
  method: "POST",
528
655
  body: formData
529
656
  });
530
657
  return res.json();
531
658
  }
532
- async function uploadLocalFile(auth, workspaceId, filePath) {
533
- const fileBuffer = fs__default.default.readFileSync(filePath);
534
- const fileName = path__default.default.basename(filePath);
535
- const result = await uploadFile(auth, workspaceId, new Blob([fileBuffer]), fileName);
536
- return { ...result, fileName };
659
+ async function uploadFiles(auth, workspaceId, files, options) {
660
+ const formData = new FormData();
661
+ for (const f of files) formData.append("files", f.data, f.name);
662
+ const params = new URLSearchParams({ workspace_ext_id: workspaceId });
663
+ if (options?.folder) params.set("folder", sanitizeFolderPath(options.folder));
664
+ const res = await authenticatedFetch({
665
+ ...auth,
666
+ path: `/v1/document/upload?${params.toString()}`,
667
+ method: "POST",
668
+ body: formData
669
+ });
670
+ return res.json();
537
671
  }
538
672
  async function downloadDocument(auth, docId) {
539
673
  return authenticatedFetch({
@@ -733,6 +867,8 @@ async function retrieve(options) {
733
867
  input: query,
734
868
  workspace_ext_id: workspaceId,
735
869
  stream: false,
870
+ background: false,
871
+ store: true,
736
872
  tools,
737
873
  ...model ? { model } : {}
738
874
  };
@@ -748,6 +884,8 @@ async function queryAssistant(options) {
748
884
  input: question,
749
885
  workspace_ext_id: workspaceId,
750
886
  stream: true,
887
+ background: false,
888
+ store: true,
751
889
  tools: {
752
890
  retrieval_chunk: buildRetrievalChunkTool(docIds),
753
891
  retrieval_full_context: buildRetrievalFullContextTool([])
@@ -1207,11 +1345,12 @@ var Arbi = class {
1207
1345
  workspaceId ?? this.requireWorkspace(),
1208
1346
  shared
1209
1347
  ),
1210
- uploadFile: (fileData, fileName, workspaceId) => uploadFile(
1348
+ uploadFile: (fileData, fileName, options) => uploadFile(
1211
1349
  this.getAuthHeaders(),
1212
- workspaceId ?? this.requireWorkspace(),
1350
+ options?.workspaceId ?? this.requireWorkspace(),
1213
1351
  fileData,
1214
- fileName
1352
+ fileName,
1353
+ options?.folder ? { folder: options.folder } : void 0
1215
1354
  ),
1216
1355
  download: (docId) => downloadDocument(this.getAuthHeaders(), docId),
1217
1356
  getParsedContent: (docId, stage) => getParsedContent(this.getAuthHeaders(), docId, stage)
@@ -1353,9 +1492,74 @@ var Arbi = class {
1353
1492
  }
1354
1493
  };
1355
1494
 
1495
+ // src/operations/responses.ts
1496
+ var responses_exports = {};
1497
+ __export(responses_exports, {
1498
+ extractResponseText: () => extractResponseText,
1499
+ getResponse: () => getResponse,
1500
+ submitBackgroundQuery: () => submitBackgroundQuery
1501
+ });
1502
+ async function submitBackgroundQuery(options) {
1503
+ const { workspaceId, question, docIds, previousResponseId, model, ...auth } = options;
1504
+ const tools = {};
1505
+ if (docIds.length > 0) {
1506
+ tools.retrieval_chunk = {
1507
+ name: "retrieval_chunk",
1508
+ description: "retrieval chunk",
1509
+ tool_args: { doc_ext_ids: docIds },
1510
+ tool_responses: {}
1511
+ };
1512
+ tools.retrieval_full_context = {
1513
+ name: "retrieval_full_context",
1514
+ description: "retrieval full context",
1515
+ tool_args: { doc_ext_ids: [] },
1516
+ tool_responses: {}
1517
+ };
1518
+ }
1519
+ const body = {
1520
+ input: question,
1521
+ workspace_ext_id: workspaceId,
1522
+ stream: false,
1523
+ background: true,
1524
+ store: true,
1525
+ tools,
1526
+ ...previousResponseId ? { previous_response_id: previousResponseId } : {},
1527
+ ...model ? { model } : {}
1528
+ };
1529
+ const res = await authenticatedFetch({
1530
+ ...auth,
1531
+ path: "/v1/responses",
1532
+ method: "POST",
1533
+ body: JSON.stringify(body),
1534
+ headers: { "Content-Type": "application/json" }
1535
+ });
1536
+ return await res.json();
1537
+ }
1538
+ async function getResponse(auth, responseId) {
1539
+ const res = await authenticatedFetch({
1540
+ ...auth,
1541
+ path: `/v1/responses/${responseId}`,
1542
+ method: "GET"
1543
+ });
1544
+ return await res.json();
1545
+ }
1546
+ function extractResponseText(response) {
1547
+ const parts = [];
1548
+ for (const msg of response.output) {
1549
+ for (const item of msg.content) {
1550
+ if ("type" in item && item.type === "output_text" && "text" in item) {
1551
+ parts.push(item.text);
1552
+ }
1553
+ }
1554
+ }
1555
+ return parts.join("");
1556
+ }
1557
+
1356
1558
  exports.Arbi = Arbi;
1357
1559
  exports.ArbiApiError = ArbiApiError;
1358
1560
  exports.ArbiError = ArbiError;
1561
+ exports.LIFECYCLE_LABELS = LIFECYCLE_LABELS;
1562
+ exports.TOOL_LABELS = TOOL_LABELS;
1359
1563
  exports.agentconfig = agentconfig_exports;
1360
1564
  exports.assistant = assistant_exports;
1361
1565
  exports.authenticatedFetch = authenticatedFetch;
@@ -1372,6 +1576,7 @@ exports.dm = dm_exports;
1372
1576
  exports.doctags = doctags_exports;
1373
1577
  exports.documents = documents_exports;
1374
1578
  exports.files = files_exports;
1579
+ exports.formatAgentStepLabel = formatAgentStepLabel;
1375
1580
  exports.formatFileSize = formatFileSize;
1376
1581
  exports.formatUserName = formatUserName;
1377
1582
  exports.formatWorkspaceChoices = formatWorkspaceChoices;
@@ -1383,6 +1588,7 @@ exports.requireData = requireData;
1383
1588
  exports.requireOk = requireOk;
1384
1589
  exports.resolveAuth = resolveAuth;
1385
1590
  exports.resolveWorkspace = resolveWorkspace;
1591
+ exports.responses = responses_exports;
1386
1592
  exports.selectWorkspace = selectWorkspace;
1387
1593
  exports.selectWorkspaceById = selectWorkspaceById;
1388
1594
  exports.settings = settings_exports;