@arbidocs/sdk 0.4.2 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- export { A as AgentControlStateEvent, a as AgentStepDeltaEvent, b as AgentStepEvent, c as Arbi, d as ArbiApiError, e as ArbiError, f as ArbiErrorEvent, g as ArbiOptions, h as ArtifactEvent, i as AuthContext, j as AuthHeaders, k as AuthenticatedClient, C as ChatSession, l as CitationSummary, m as CliConfig, n as CliCredentials, o as CommandDescriptor, p as ConfigStore, q as ConnectOptions, r as CreateFactRequest, s as CreateFactsRequest, t as CreateTaskRequest, u as DeferredInterjectionEvent, F as FactResponse, E as FactSearchRequest, G as FactSearchResponse, I as ListFactsOptions, K as MessageMetadataPayload, N as MessageQueuedEvent, O as OutputTokensDetails, P as ParsedSlashCommand, Q as ProbeAnswerEvent, R as ProjectInvoicesResponse, S as ProjectUsageResponse, T as QueryOptions, U as ReconnectOptions, V as ReconnectableWsConnection, W as ResolvedCitation, Y as ResponseCompletedEvent, Z as ResponseContentPartAddedEvent, _ as ResponseCreatedEvent, $ as ResponseFailedEvent, a0 as ResponseOutputItemAddedEvent, a1 as ResponseOutputItemDoneEvent, a2 as ResponseOutputTextDeltaEvent, a3 as ResponseOutputTextDoneEvent, a4 as ResponseUsage, a5 as SSEEvent, a6 as SSEStreamCallbacks, a7 as SSEStreamResult, a8 as SSEStreamStartData, aa as SkillSummary, ac as TaskResponse, ad as TokenBudgetContext, ae as UpdateFactRequest, af as UpdateTaskRequest, al as UserDailyUsageResponse, am as UserInfo, an as UserInputRequestEvent, ao as UserMessageEvent, ap as WebSocketAuthError, aq as WorkspaceContext, ar as WsConnection, as as agentconfig, at as assistant, au as authenticatedFetch, aw as buildRetrievalChunkTool, ax as buildRetrievalFullContextTool, ay as buildRetrievalTocTool, az as connectWebSocket, aA as connectWithReconnect, aB as consumeSSEStream, aC as contacts, aD as conversations, aE as countCitations, aF as createAuthenticatedClient, aH as dm, aI as doctags, aJ as documents, aK as facts, aL as files, aM as filterSkills, aN as formatAgentStepLabel, aO as formatFileSize, aP as formatItemLabel, aR as formatUserName, aS as formatWorkspaceChoices, aX as getErrorMessage, aY as getRawWorkspaceKey, aZ as health, a_ as parseSSEEvents, a$ as parseSlashCommand, b0 as parseSlashTokenInProgress, b1 as performPasswordLogin, b4 as projects, b5 as requireData, b6 as requireOk, b7 as resolveAuth, b8 as resolveCitations, b9 as resolveWorkspace, ba as responses, bb as selectWorkspace, bc as selectWorkspaceById, bd as settings, be as streamSSE, bf as stripCitationMarkdown, bg as summarizeCitations, bh as tags, bi as tasks, bj as workspaces } from './browser-U90kdb7T.cjs';
1
+ export { A as AgentControlStateEvent, a as AgentStepDeltaEvent, b as AgentStepEvent, c as Arbi, d as ArbiApiError, e as ArbiError, f as ArbiErrorEvent, g as ArbiOptions, i as ArtifactEvent, j as AuthContext, k as AuthHeaders, l as AuthenticatedClient, C as ChatSession, m as CitationSummary, n as CliConfig, o as CliCredentials, p as CommandDescriptor, q as ConfigStore, r as ConnectOptions, s as CreateFactRequest, t as CreateFactsRequest, u as CreateTaskRequest, v as DeferredInterjectionEvent, F as FactResponse, G as FactSearchRequest, H as FactSearchResponse, J as ListFactsOptions, N as MessageMetadataPayload, O as MessageQueuedEvent, P as OutputTokensDetails, Q as ParsedSlashCommand, R as ProbeAnswerEvent, S as ProjectInvoicesResponse, T as ProjectUsageResponse, U as QueryOptions, V as ReconnectOptions, W as ReconnectableWsConnection, X as ResolvedCitation, Z as ResponseCompletedEvent, _ as ResponseContentPartAddedEvent, $ as ResponseCreatedEvent, a0 as ResponseFailedEvent, a1 as ResponseOutputItemAddedEvent, a2 as ResponseOutputItemDoneEvent, a3 as ResponseOutputTextDeltaEvent, a4 as ResponseOutputTextDoneEvent, a5 as ResponseUsage, a6 as SSEEvent, a7 as SSEStreamCallbacks, a8 as SSEStreamResult, a9 as SSEStreamStartData, ab as SkillSummary, ad as TaskResponse, ae as TokenBudgetContext, af as UpdateFactRequest, ag as UpdateTaskRequest, am as UserDailyUsageResponse, an as UserInfo, ao as UserInputRequestEvent, ap as UserMessageEvent, aq as WebSocketAuthError, ar as WorkspaceContext, as as WsConnection, at as agentconfig, au as assistant, av as authenticatedFetch, ax as buildRetrievalChunkTool, ay as buildRetrievalFullContextTool, az as buildRetrievalTocTool, aA as connectWebSocket, aB as connectWithReconnect, aC as consumeSSEStream, aD as contacts, aE as conversations, aF as countCitations, aG as createAuthenticatedClient, aI as dm, aJ as doctags, aK as documents, aL as facts, aM as files, aN as filterSkills, aO as formatAgentStepLabel, aP as formatFileSize, aQ as formatItemLabel, aS as formatUserName, aT as formatWorkspaceChoices, aY as getErrorMessage, aZ as getRawWorkspaceKey, a_ as health, a$ as parseSSEEvents, b0 as parseSlashCommand, b1 as parseSlashTokenInProgress, b2 as performPasswordLogin, b5 as projects, b6 as requireData, b7 as requireOk, b8 as resolveAuth, b9 as resolveCitations, ba as resolveWorkspace, bb as responses, bc as selectWorkspace, bd as selectWorkspaceById, be as settings, bf as streamSSE, bg as stripCitationMarkdown, bh as summarizeCitations, bi as tags, bj as tasks, bk as workspaces } from './browser-Bdzn5DIN.cjs';
2
2
  import '@arbidocs/client';
package/dist/browser.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { A as AgentControlStateEvent, a as AgentStepDeltaEvent, b as AgentStepEvent, c as Arbi, d as ArbiApiError, e as ArbiError, f as ArbiErrorEvent, g as ArbiOptions, h as ArtifactEvent, i as AuthContext, j as AuthHeaders, k as AuthenticatedClient, C as ChatSession, l as CitationSummary, m as CliConfig, n as CliCredentials, o as CommandDescriptor, p as ConfigStore, q as ConnectOptions, r as CreateFactRequest, s as CreateFactsRequest, t as CreateTaskRequest, u as DeferredInterjectionEvent, F as FactResponse, E as FactSearchRequest, G as FactSearchResponse, I as ListFactsOptions, K as MessageMetadataPayload, N as MessageQueuedEvent, O as OutputTokensDetails, P as ParsedSlashCommand, Q as ProbeAnswerEvent, R as ProjectInvoicesResponse, S as ProjectUsageResponse, T as QueryOptions, U as ReconnectOptions, V as ReconnectableWsConnection, W as ResolvedCitation, Y as ResponseCompletedEvent, Z as ResponseContentPartAddedEvent, _ as ResponseCreatedEvent, $ as ResponseFailedEvent, a0 as ResponseOutputItemAddedEvent, a1 as ResponseOutputItemDoneEvent, a2 as ResponseOutputTextDeltaEvent, a3 as ResponseOutputTextDoneEvent, a4 as ResponseUsage, a5 as SSEEvent, a6 as SSEStreamCallbacks, a7 as SSEStreamResult, a8 as SSEStreamStartData, aa as SkillSummary, ac as TaskResponse, ad as TokenBudgetContext, ae as UpdateFactRequest, af as UpdateTaskRequest, al as UserDailyUsageResponse, am as UserInfo, an as UserInputRequestEvent, ao as UserMessageEvent, ap as WebSocketAuthError, aq as WorkspaceContext, ar as WsConnection, as as agentconfig, at as assistant, au as authenticatedFetch, aw as buildRetrievalChunkTool, ax as buildRetrievalFullContextTool, ay as buildRetrievalTocTool, az as connectWebSocket, aA as connectWithReconnect, aB as consumeSSEStream, aC as contacts, aD as conversations, aE as countCitations, aF as createAuthenticatedClient, aH as dm, aI as doctags, aJ as documents, aK as facts, aL as files, aM as filterSkills, aN as formatAgentStepLabel, aO as formatFileSize, aP as formatItemLabel, aR as formatUserName, aS as formatWorkspaceChoices, aX as getErrorMessage, aY as getRawWorkspaceKey, aZ as health, a_ as parseSSEEvents, a$ as parseSlashCommand, b0 as parseSlashTokenInProgress, b1 as performPasswordLogin, b4 as projects, b5 as requireData, b6 as requireOk, b7 as resolveAuth, b8 as resolveCitations, b9 as resolveWorkspace, ba as responses, bb as selectWorkspace, bc as selectWorkspaceById, bd as settings, be as streamSSE, bf as stripCitationMarkdown, bg as summarizeCitations, bh as tags, bi as tasks, bj as workspaces } from './browser-U90kdb7T.js';
1
+ export { A as AgentControlStateEvent, a as AgentStepDeltaEvent, b as AgentStepEvent, c as Arbi, d as ArbiApiError, e as ArbiError, f as ArbiErrorEvent, g as ArbiOptions, i as ArtifactEvent, j as AuthContext, k as AuthHeaders, l as AuthenticatedClient, C as ChatSession, m as CitationSummary, n as CliConfig, o as CliCredentials, p as CommandDescriptor, q as ConfigStore, r as ConnectOptions, s as CreateFactRequest, t as CreateFactsRequest, u as CreateTaskRequest, v as DeferredInterjectionEvent, F as FactResponse, G as FactSearchRequest, H as FactSearchResponse, J as ListFactsOptions, N as MessageMetadataPayload, O as MessageQueuedEvent, P as OutputTokensDetails, Q as ParsedSlashCommand, R as ProbeAnswerEvent, S as ProjectInvoicesResponse, T as ProjectUsageResponse, U as QueryOptions, V as ReconnectOptions, W as ReconnectableWsConnection, X as ResolvedCitation, Z as ResponseCompletedEvent, _ as ResponseContentPartAddedEvent, $ as ResponseCreatedEvent, a0 as ResponseFailedEvent, a1 as ResponseOutputItemAddedEvent, a2 as ResponseOutputItemDoneEvent, a3 as ResponseOutputTextDeltaEvent, a4 as ResponseOutputTextDoneEvent, a5 as ResponseUsage, a6 as SSEEvent, a7 as SSEStreamCallbacks, a8 as SSEStreamResult, a9 as SSEStreamStartData, ab as SkillSummary, ad as TaskResponse, ae as TokenBudgetContext, af as UpdateFactRequest, ag as UpdateTaskRequest, am as UserDailyUsageResponse, an as UserInfo, ao as UserInputRequestEvent, ap as UserMessageEvent, aq as WebSocketAuthError, ar as WorkspaceContext, as as WsConnection, at as agentconfig, au as assistant, av as authenticatedFetch, ax as buildRetrievalChunkTool, ay as buildRetrievalFullContextTool, az as buildRetrievalTocTool, aA as connectWebSocket, aB as connectWithReconnect, aC as consumeSSEStream, aD as contacts, aE as conversations, aF as countCitations, aG as createAuthenticatedClient, aI as dm, aJ as doctags, aK as documents, aL as facts, aM as files, aN as filterSkills, aO as formatAgentStepLabel, aP as formatFileSize, aQ as formatItemLabel, aS as formatUserName, aT as formatWorkspaceChoices, aY as getErrorMessage, aZ as getRawWorkspaceKey, a_ as health, a$ as parseSSEEvents, b0 as parseSlashCommand, b1 as parseSlashTokenInProgress, b2 as performPasswordLogin, b5 as projects, b6 as requireData, b7 as requireOk, b8 as resolveAuth, b9 as resolveCitations, ba as resolveWorkspace, bb as responses, bc as selectWorkspace, bd as selectWorkspaceById, be as settings, bf as streamSSE, bg as stripCitationMarkdown, bh as summarizeCitations, bi as tags, bj as tasks, bk as workspaces } from './browser-Bdzn5DIN.js';
2
2
  import '@arbidocs/client';
package/dist/browser.js CHANGED
@@ -3481,6 +3481,12 @@ var ArbiError = class extends Error {
3481
3481
  this.name = "ArbiError";
3482
3482
  }
3483
3483
  };
3484
+ var ArbiSessionExpiredError = class extends ArbiError {
3485
+ constructor(message = "Your session expired. Sign in again.") {
3486
+ super(message);
3487
+ this.name = "ArbiSessionExpiredError";
3488
+ }
3489
+ };
3484
3490
  var ArbiApiError = class extends ArbiError {
3485
3491
  apiError;
3486
3492
  constructor(message, apiError) {
@@ -3635,6 +3641,16 @@ async function selectWorkspace(arbi, workspaceId, wrappedKey, serverSessionKey,
3635
3641
  arbi.session.setSelectedWorkspace(workspaceId);
3636
3642
  return header;
3637
3643
  }
3644
+ async function generateEncryptedWorkspaceKey(arbi, wrappedKey, serverSessionKey, signingPrivateKeyBase64) {
3645
+ const signingPrivateKey = base64ToBytes(signingPrivateKeyBase64);
3646
+ const ed25519PublicKey = signingPrivateKey.slice(32, 64);
3647
+ const encryptionKeyPair = deriveEncryptionKeypairFromSigning({
3648
+ publicKey: ed25519PublicKey,
3649
+ secretKey: signingPrivateKey
3650
+ });
3651
+ const workspaceKey = sealedBoxDecrypt(wrappedKey, encryptionKeyPair.secretKey);
3652
+ return sealKeyForSession(workspaceKey, serverSessionKey);
3653
+ }
3638
3654
  async function getRawWorkspaceKey(arbi, workspaceId, signingPrivateKeyBase64) {
3639
3655
  const { data: workspaces, error } = await arbi.fetch.GET("/v1/user/workspaces");
3640
3656
  if (error || !workspaces) {
@@ -4657,6 +4673,7 @@ __export(workspaces_exports, {
4657
4673
  copyDocuments: () => copyDocuments,
4658
4674
  createWorkspace: () => createWorkspace,
4659
4675
  deleteWorkspaces: () => deleteWorkspaces,
4676
+ grantTemporaryWorkspaceAccess: () => grantTemporaryWorkspaceAccess,
4660
4677
  listWorkspaceUsers: () => listWorkspaceUsers,
4661
4678
  listWorkspaces: () => listWorkspaces,
4662
4679
  removeWorkspaceUsers: () => removeWorkspaceUsers,
@@ -4697,14 +4714,33 @@ async function updateWorkspace(arbi, body) {
4697
4714
  async function listWorkspaceUsers(arbi) {
4698
4715
  return requireData(await arbi.fetch.GET("/v1/workspace/users"), "Failed to fetch workspace users");
4699
4716
  }
4700
- async function addWorkspaceUsers(arbi, emails, role = "collaborator") {
4717
+ async function addWorkspaceUsers(arbi, emails, role = "collaborator", target) {
4701
4718
  return requireData(
4702
4719
  await arbi.fetch.POST("/v1/workspace/users", {
4703
- body: { emails, role }
4720
+ body: target ? {
4721
+ emails,
4722
+ role,
4723
+ workspace_ext_id: target.workspaceExtId,
4724
+ workspace_key: target.workspaceKey
4725
+ } : { emails, role }
4704
4726
  }),
4705
4727
  "Failed to add users"
4706
4728
  );
4707
4729
  }
4730
+ async function grantTemporaryWorkspaceAccess(arbi, params) {
4731
+ return requireData(
4732
+ await arbi.fetch.POST("/v1/workspace/users", {
4733
+ body: {
4734
+ emails: params.emails,
4735
+ role: params.role ?? "collaborator",
4736
+ workspace_ext_id: params.workspaceExtId,
4737
+ workspace_key: params.workspaceKey,
4738
+ session_pubkey_b64: params.sessionPubkeyB64
4739
+ }
4740
+ }),
4741
+ "Failed to grant temporary access"
4742
+ );
4743
+ }
4708
4744
  async function removeWorkspaceUsers(arbi, userIds) {
4709
4745
  requireOk(
4710
4746
  await arbi.fetch.DELETE("/v1/workspace/users", {
@@ -5129,6 +5165,21 @@ async function deleteAgents(arbi, agentExtIds) {
5129
5165
  "Failed to delete agents"
5130
5166
  );
5131
5167
  }
5168
+ async function authorizeAgent(arbi, agentExtId, workspaceExtId, ttlSeconds) {
5169
+ return requireData(
5170
+ await arbi.fetch.POST("/v1/agents/{agent_ext_id}/authorize", {
5171
+ params: { path: { agent_ext_id: agentExtId } },
5172
+ body: { workspace_ext_id: workspaceExtId, ttl_seconds: ttlSeconds ?? null }
5173
+ }),
5174
+ "Failed to authorize agent"
5175
+ );
5176
+ }
5177
+ async function getAuthorizeLimits(arbi) {
5178
+ return requireData(
5179
+ await arbi.fetch.GET("/v1/agents/authorize-limits"),
5180
+ "Failed to fetch authorize limits"
5181
+ );
5182
+ }
5132
5183
 
5133
5184
  // src/operations/dm.ts
5134
5185
  function createDmCryptoContext(arbi, signingPrivateKeyBytes, userExtId) {
@@ -5511,6 +5562,7 @@ __export(tasks_exports, {
5511
5562
  createTask: () => createTask,
5512
5563
  deleteTask: () => deleteTask,
5513
5564
  getTask: () => getTask,
5565
+ listTaskRuns: () => listTaskRuns,
5514
5566
  listTasks: () => listTasks,
5515
5567
  runTask: () => runTask,
5516
5568
  updateTask: () => updateTask
@@ -5548,6 +5600,12 @@ async function runTask(arbi, taskId) {
5548
5600
  "Failed to run task"
5549
5601
  );
5550
5602
  }
5603
+ async function listTaskRuns(arbi, taskId) {
5604
+ return requireData(
5605
+ await arbi.fetch.GET("/v1/tasks/{task_id}/runs", { params: { path: { task_id: taskId } } }),
5606
+ "Failed to list task runs"
5607
+ );
5608
+ }
5551
5609
 
5552
5610
  // src/operations/facts.ts
5553
5611
  var facts_exports = {};
@@ -5617,11 +5675,23 @@ async function remindFact(arbi, factId, options = {}) {
5617
5675
  }
5618
5676
 
5619
5677
  // src/arbi.ts
5678
+ function tokenExpiresWithin(token, seconds) {
5679
+ const payload = token?.split(".")[1];
5680
+ if (!payload) return false;
5681
+ try {
5682
+ const json = atob(payload.replace(/-/g, "+").replace(/_/g, "/"));
5683
+ const { exp } = JSON.parse(json);
5684
+ return typeof exp === "number" && exp * 1e3 - Date.now() < seconds * 1e3;
5685
+ } catch {
5686
+ return false;
5687
+ }
5688
+ }
5620
5689
  var Arbi = class {
5621
5690
  client = null;
5622
5691
  loginResult = null;
5623
5692
  currentWorkspaceId = null;
5624
5693
  dmCryptoContext = null;
5694
+ sessionExpiredListeners = /* @__PURE__ */ new Set();
5625
5695
  options;
5626
5696
  constructor(options) {
5627
5697
  this.options = options;
@@ -5634,7 +5704,13 @@ var Arbi = class {
5634
5704
  this.client = createArbiClient({
5635
5705
  baseUrl: this.options.url,
5636
5706
  deploymentDomain: domain,
5637
- credentials: this.options.credentials ?? "omit"
5707
+ credentials: this.options.credentials ?? "omit",
5708
+ // A silent re-login rotates the server session key: keep ours in step, or the next
5709
+ // workspace open would seal the key for a session the server no longer has.
5710
+ onReloginSuccess: ({ serverSessionKey }) => {
5711
+ if (this.loginResult) this.loginResult = { ...this.loginResult, serverSessionKey };
5712
+ },
5713
+ onSessionExpired: () => this.expireSession()
5638
5714
  });
5639
5715
  await this.client.crypto.initSodium();
5640
5716
  return this.client;
@@ -5671,6 +5747,22 @@ var Arbi = class {
5671
5747
  const signingPrivateKey = client.crypto.base64ToBytes(signingPrivateKeyBase64);
5672
5748
  this.loginResult = await client.auth.loginWithKey({ email, signingPrivateKey });
5673
5749
  }
5750
+ /** A workspace's key, sealed to the caller's own session (what `/open` and `POST /workspace/users` take). */
5751
+ async sealWorkspaceKey(workspaceId) {
5752
+ const client = this.requireClient();
5753
+ const lr2 = this.requireLogin();
5754
+ const all = await listWorkspaces(client);
5755
+ const ws = all.find((w2) => w2.external_id === workspaceId);
5756
+ if (!ws || !ws.wrapped_key) {
5757
+ throw new ArbiError(`Workspace ${workspaceId} not found or has no encryption key`);
5758
+ }
5759
+ return generateEncryptedWorkspaceKey(
5760
+ client,
5761
+ ws.wrapped_key,
5762
+ lr2.serverSessionKey,
5763
+ client.crypto.bytesToBase64(lr2.signingPrivateKey)
5764
+ );
5765
+ }
5674
5766
  /**
5675
5767
  * Select a workspace by ID. Fetches the workspace list, finds the matching
5676
5768
  * workspace, decrypts the wrapped key, and sets up auth headers.
@@ -5697,6 +5789,52 @@ var Arbi = class {
5697
5789
  });
5698
5790
  this.currentWorkspaceId = ws.external_id;
5699
5791
  }
5792
+ /**
5793
+ * Subscribe to "the session cannot be recovered". Fires when a request failed with 401 or
5794
+ * "No active workspace" and neither a workspace re-open nor a silent re-login was possible
5795
+ * (the server refused; an unreachable server does not fire). The local session is already
5796
+ * cleared when it fires: show "Your session expired, sign in again". Returns an unsubscribe.
5797
+ */
5798
+ onSessionExpired(listener) {
5799
+ this.sessionExpiredListeners.add(listener);
5800
+ return () => this.sessionExpiredListeners.delete(listener);
5801
+ }
5802
+ expireSession() {
5803
+ if (this.loginResult) {
5804
+ this.loginResult.signingPrivateKey.fill(0);
5805
+ this.loginResult.serverSessionKey.fill(0);
5806
+ }
5807
+ this.loginResult = null;
5808
+ this.currentWorkspaceId = null;
5809
+ this.dmCryptoContext = null;
5810
+ this.client?.session.clear();
5811
+ for (const listener of [...this.sessionExpiredListeners]) listener();
5812
+ }
5813
+ /**
5814
+ * Run a raw-fetch operation (streaming, multipart: no middleware) and, when it fails because
5815
+ * the token expired or the server lost the open workspace, recover once and run it again.
5816
+ * `run` must read the auth headers itself so the retry carries the fresh token.
5817
+ */
5818
+ async recovering(run) {
5819
+ if (this.client && tokenExpiresWithin(this.client.session.getState().accessToken, 30)) {
5820
+ await this.client.auth.relogin();
5821
+ }
5822
+ try {
5823
+ return await run();
5824
+ } catch (error) {
5825
+ const message = error instanceof Error ? error.message : "";
5826
+ const noWorkspace = /no active workspace/i.test(message);
5827
+ const unauthorised = /\b401\b|token has expired/i.test(message);
5828
+ if (!(error instanceof ArbiApiError) || !(noWorkspace || unauthorised)) throw error;
5829
+ const client = this.requireClient();
5830
+ const recovered = noWorkspace && await client.auth.reopenWorkspace() || await client.auth.relogin() !== null;
5831
+ if (!recovered) {
5832
+ this.expireSession();
5833
+ throw new ArbiSessionExpiredError();
5834
+ }
5835
+ return run();
5836
+ }
5837
+ }
5700
5838
  /** Log out and clear internal state. */
5701
5839
  async logout() {
5702
5840
  if (this.client) {
@@ -5807,6 +5945,30 @@ var Arbi = class {
5807
5945
  update: (body) => updateWorkspace(this.requireClient(), body),
5808
5946
  listUsers: () => listWorkspaceUsers(this.requireClient()),
5809
5947
  addUsers: (emails, role) => addWorkspaceUsers(this.requireClient(), emails, role),
5948
+ /**
5949
+ * Grant users a temporary key scoped to ONE session (identified by its public key), for
5950
+ * example an agent's run session minted by `agents.authorize()`. Nothing standing is created:
5951
+ * the grant expires with that session. Works for any workspace the caller holds a key for;
5952
+ * it does not need to be the open one.
5953
+ */
5954
+ grantTemporaryAccess: async (params) => {
5955
+ const client = this.requireClient();
5956
+ return grantTemporaryWorkspaceAccess(client, {
5957
+ emails: params.emails,
5958
+ workspaceExtId: params.workspaceId,
5959
+ workspaceKey: await this.sealWorkspaceKey(params.workspaceId),
5960
+ sessionPubkeyB64: params.sessionPubkeyB64,
5961
+ role: params.role
5962
+ });
5963
+ },
5964
+ /**
5965
+ * Add users (standing, permanent membership) to ANY workspace the caller holds a key for,
5966
+ * without opening it. `addUsers` does the same for the currently open workspace.
5967
+ */
5968
+ grantAccess: async (params) => addWorkspaceUsers(this.requireClient(), params.emails, params.role, {
5969
+ workspaceExtId: params.workspaceId,
5970
+ workspaceKey: await this.sealWorkspaceKey(params.workspaceId)
5971
+ }),
5810
5972
  removeUsers: (userIds) => removeWorkspaceUsers(this.requireClient(), userIds),
5811
5973
  setUserRole: (userIds, role) => setUserRole(this.requireClient(), userIds, role),
5812
5974
  /**
@@ -5863,16 +6025,18 @@ var Arbi = class {
5863
6025
  },
5864
6026
  uploadFile: (fileData, fileName, options) => {
5865
6027
  this.requireWorkspace();
5866
- return uploadFile(
5867
- this.getAuthHeaders(),
5868
- fileData,
5869
- fileName,
5870
- options?.folder ? { folder: options.folder } : void 0
6028
+ return this.recovering(
6029
+ () => uploadFile(
6030
+ this.getAuthHeaders(),
6031
+ fileData,
6032
+ fileName,
6033
+ options?.folder ? { folder: options.folder } : void 0
6034
+ )
5871
6035
  );
5872
6036
  },
5873
- download: (docId) => downloadDocument(this.getAuthHeaders(), docId),
5874
- getParsedContent: (docId, stage) => getParsedContent(this.getAuthHeaders(), docId, stage),
5875
- getThumbnails: (docIds) => getThumbnails(this.getAuthHeaders(), docIds)
6037
+ download: (docId) => this.recovering(() => downloadDocument(this.getAuthHeaders(), docId)),
6038
+ getParsedContent: (docId, stage) => this.recovering(() => getParsedContent(this.getAuthHeaders(), docId, stage)),
6039
+ getThumbnails: (docIds) => this.recovering(() => getThumbnails(this.getAuthHeaders(), docIds))
5876
6040
  };
5877
6041
  // ── Conversations ─────────────────────────────────────────────────────
5878
6042
  conversations = {
@@ -5891,16 +6055,17 @@ var Arbi = class {
5891
6055
  * Returns the accumulated result after the stream completes.
5892
6056
  */
5893
6057
  query: async (question, options) => {
5894
- const auth = this.getAuthHeaders();
5895
6058
  const workspaceId = this.requireWorkspace();
5896
- const response = await queryAssistant({
5897
- ...auth,
5898
- workspaceId,
5899
- question,
5900
- docIds: options.docIds,
5901
- previousResponseId: options.previousResponseId,
5902
- model: options.model
5903
- });
6059
+ const response = await this.recovering(
6060
+ () => queryAssistant({
6061
+ ...this.getAuthHeaders(),
6062
+ workspaceId,
6063
+ question,
6064
+ docIds: options.docIds,
6065
+ previousResponseId: options.previousResponseId,
6066
+ model: options.model
6067
+ })
6068
+ );
5904
6069
  const callbacks = {
5905
6070
  onToken: options.onToken,
5906
6071
  onStreamStart: options.onStreamStart,
@@ -5919,6 +6084,8 @@ var Arbi = class {
5919
6084
  * Respond to an agent's question during a human-in-the-loop workflow.
5920
6085
  */
5921
6086
  respond: (assistantMessageExtId, answer) => respondToAgent(this.requireClient(), assistantMessageExtId, answer),
6087
+ /** The skills the caller can run (own + shared marketplace), metadata only. */
6088
+ listSkills: (options) => listSkills(this.requireClient(), options),
5922
6089
  /**
5923
6090
  * Search documents without LLM generation (retrieval only).
5924
6091
  */
@@ -6064,8 +6231,10 @@ var Arbi = class {
6064
6231
  list: (options) => listFiles(this.requireClient(), options),
6065
6232
  get: (fileId) => getFile(this.requireClient(), fileId),
6066
6233
  delete: (fileId) => deleteFile(this.requireClient(), fileId),
6067
- upload: (fileData, fileName, purpose) => uploadFile2(this.getAuthHeaders(), fileData, fileName, purpose),
6068
- getContent: (fileId) => getFileContent(this.getAuthHeaders(), fileId)
6234
+ upload: (fileData, fileName, purpose) => this.recovering(
6235
+ () => uploadFile2(this.getAuthHeaders(), fileData, fileName, purpose)
6236
+ ),
6237
+ getContent: (fileId) => this.recovering(() => getFileContent(this.getAuthHeaders(), fileId))
6069
6238
  };
6070
6239
  // ── Agents ──────────────────────────────────────────────────────────
6071
6240
  agents = {
@@ -6073,7 +6242,28 @@ var Arbi = class {
6073
6242
  create: (name) => createAgent(this.requireClient(), name),
6074
6243
  getConfig: (agentExtId) => getAgentConfig(this.requireClient(), agentExtId),
6075
6244
  listWorkspaces: (agentExtId) => listAgentWorkspaces(this.requireClient(), agentExtId),
6076
- delete: (agentExtIds) => deleteAgents(this.requireClient(), agentExtIds)
6245
+ delete: (agentExtIds) => deleteAgents(this.requireClient(), agentExtIds),
6246
+ /** Mint a TTL'd run session for an agent; see `grantTemporaryAccess` to also deposit a key. */
6247
+ authorize: (agentExtId, workspaceId, ttlSeconds) => authorizeAgent(this.requireClient(), agentExtId, workspaceId, ttlSeconds),
6248
+ authorizeLimits: () => getAuthorizeLimits(this.requireClient()),
6249
+ /**
6250
+ * Give an agent temporary, session-scoped access to a workspace: mint its run session, then
6251
+ * deposit the workspace key on it. Returns the session details (`ttl` in seconds).
6252
+ */
6253
+ grantTemporaryAccess: async (agentExtId, workspaceId, ttlSeconds) => {
6254
+ const session = await authorizeAgent(
6255
+ this.requireClient(),
6256
+ agentExtId,
6257
+ workspaceId,
6258
+ ttlSeconds
6259
+ );
6260
+ await this.workspaces.grantTemporaryAccess({
6261
+ workspaceId,
6262
+ emails: [session.agent_email],
6263
+ sessionPubkeyB64: session.session_pubkey_b64
6264
+ });
6265
+ return session;
6266
+ }
6077
6267
  };
6078
6268
  // ── Scheduled tasks ───────────────────────────────────────────────────
6079
6269
  tasks = {
@@ -6082,7 +6272,26 @@ var Arbi = class {
6082
6272
  get: (taskId) => getTask(this.requireClient(), taskId),
6083
6273
  update: (taskId, body) => updateTask(this.requireClient(), taskId, body),
6084
6274
  delete: (taskId) => deleteTask(this.requireClient(), taskId),
6085
- run: (taskId) => runTask(this.requireClient(), taskId)
6275
+ run: (taskId) => runTask(this.requireClient(), taskId),
6276
+ listRuns: (taskId) => listTaskRuns(this.requireClient(), taskId),
6277
+ /**
6278
+ * Run a task and, when the run is parked waiting for workspace access (a temporary
6279
+ * authorization tier), grant the agent's run session a temporary key and run it again.
6280
+ * A task that needs no approval returns from the first call already running.
6281
+ */
6282
+ runWithAuth: async (taskId) => {
6283
+ const client = this.requireClient();
6284
+ const first = await runTask(client, taskId);
6285
+ if (!first.pending_auth_request_id || !first.pending_auth_session_pubkey || !first.pending_auth_agent_email || !first.workspace_ext_id) {
6286
+ return first;
6287
+ }
6288
+ await this.workspaces.grantTemporaryAccess({
6289
+ workspaceId: first.workspace_ext_id,
6290
+ emails: [first.pending_auth_agent_email],
6291
+ sessionPubkeyB64: first.pending_auth_session_pubkey
6292
+ });
6293
+ return runTask(client, taskId);
6294
+ }
6086
6295
  };
6087
6296
  // ── Workspace facts ─────────────────────────────────────────────────
6088
6297
  facts = {