@alfe.ai/agent-api-client 0.14.0 → 0.15.0

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/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # @alfe.ai/agent-api-client
2
2
 
3
- Agent self-service API client agents calling /agents/ endpoints
3
+ Agent self-service API client for Alfe's agent-authenticated endpoints. It
4
+ resolves identity from the bearer token, so callers never place their own
5
+ `agentId` in a self-service path.
4
6
 
5
7
  Part of [**Alfe**](https://alfe.ai) — the operating system for AI agents: build, deploy, and run agents with persistent memory, identity, integrations, and channels. See the [documentation](https://docs.alfe.ai) to get started.
6
8
 
@@ -10,6 +12,26 @@ Part of [**Alfe**](https://alfe.ai) — the operating system for AI agents: buil
10
12
  npm install @alfe.ai/agent-api-client
11
13
  ```
12
14
 
15
+ ## Usage
16
+
17
+ ```ts
18
+ import { AgentApiClient } from "@alfe.ai/agent-api-client";
19
+
20
+ const client = new AgentApiClient({ apiKey, apiUrl });
21
+ const manifest = await client.syncGetManifest();
22
+ ```
23
+
24
+ Construct one client for the daemon/plugin lifetime and reuse it. JSON methods
25
+ unwrap Alfe's `{ data }` response envelope and attach the HTTP status to thrown
26
+ errors. Safe reads retry one transient failure; mutations do not retry unless a
27
+ method has an explicit server-side idempotency contract. S3 presigned URLs and
28
+ raw voice audio use their dedicated binary/direct-transfer paths.
29
+
30
+ The flat `AgentApiClient` surface is assembled from domain modules for chat,
31
+ Connect credentials, database, identity, integrations, knowledge, memory,
32
+ mobile, search, secrets, sync/shared files, voice, webhooks, and workspace
33
+ configuration.
34
+
13
35
  ## Links
14
36
 
15
37
  - 🌐 Website: <https://alfe.ai>
package/dist/index.cjs CHANGED
@@ -20,7 +20,14 @@ function firstFrame(err) {
20
20
  return frame ? ` (${frame.trim()})` : "";
21
21
  }
22
22
  function buildLine(plugin, tool, kind, message, frame = "") {
23
- return `[ERROR] alfe-tool plugin=${plugin} tool=${tool} ${kind}: ${message.replace(/\s+/g, " ").trim()}${frame}`.slice(0, 480);
23
+ const safeToken = (value) => value.replace(/[^A-Za-z0-9_.@/-]+/g, "_").slice(0, 80);
24
+ const stripControls = (value) => Array.from(value, (character) => {
25
+ const code = character.charCodeAt(0);
26
+ return code < 32 || code >= 127 && code <= 159 ? " " : character;
27
+ }).join("");
28
+ const oneLine = stripControls(message).replace(/\s+/g, " ").trim();
29
+ const safeFrame = stripControls(frame).replace(/\s+/g, " ");
30
+ return `[ERROR] alfe-tool plugin=${safeToken(plugin)} tool=${safeToken(tool)} ${kind}: ${oneLine}${safeFrame}`.slice(0, 480);
24
31
  }
25
32
  function wrapExecute(tool, opts) {
26
33
  const execute = tool.execute;
@@ -57,7 +64,6 @@ function installToolErrorCapture(api, options) {
57
64
  try {
58
65
  const markedApi = api;
59
66
  if (markedApi[INSTALLED_MARKER]) return;
60
- markedApi[INSTALLED_MARKER] = true;
61
67
  const emit = options.emit ?? ((line) => {
62
68
  process.stderr.write(`${line}\n`);
63
69
  });
@@ -66,24 +72,29 @@ function installToolErrorCapture(api, options) {
66
72
  emit
67
73
  };
68
74
  const original = api.registerTool.bind(api);
69
- api.registerTool = (...args) => {
75
+ const wrappedRegisterTool = (...args) => {
76
+ let preparedArgs = args;
70
77
  try {
71
78
  const [first, ...rest] = args;
72
79
  if (typeof first === "function") {
73
80
  const factory = first;
74
81
  const wrappedFactory = (...fa) => {
75
82
  const tool = factory(...fa);
76
- if (typeof tool === "object" && tool !== null) wrapExecute(tool, opts);
83
+ if (typeof tool === "object" && tool !== null) try {
84
+ wrapExecute(tool, opts);
85
+ } catch {}
77
86
  return tool;
78
87
  };
79
- return original(wrappedFactory, ...rest);
88
+ preparedArgs = [wrappedFactory, ...rest];
80
89
  }
81
90
  if (typeof first === "object" && first !== null) wrapExecute(first, opts);
82
- return original(first, ...rest);
83
91
  } catch {
84
- return original(...args);
92
+ preparedArgs = args;
85
93
  }
94
+ return original(...preparedArgs);
86
95
  };
96
+ api.registerTool = wrappedRegisterTool;
97
+ markedApi[INSTALLED_MARKER] = true;
87
98
  } catch {}
88
99
  }
89
100
  //#endregion
@@ -122,6 +133,10 @@ const RETRYABLE_STATUS = new Set([
122
133
  504
123
134
  ]);
124
135
  const RETRY_DELAY_MS = 500;
136
+ function isSafeRetryMethod(method) {
137
+ const normalized = (method ?? "GET").toUpperCase();
138
+ return normalized === "GET" || normalized === "HEAD" || normalized === "OPTIONS";
139
+ }
125
140
  function sleep(ms) {
126
141
  return new Promise((resolve) => {
127
142
  setTimeout(resolve, ms);
@@ -133,6 +148,12 @@ function isRetryableNetworkError(err) {
133
148
  if (err.name === "TypeError") return true;
134
149
  return false;
135
150
  }
151
+ /** Whether a completed request may be retried/polled without masking a real client error. */
152
+ function isTransientRequestError(err) {
153
+ if (isRetryableNetworkError(err)) return true;
154
+ const status = err?.status;
155
+ return typeof status === "number" && RETRYABLE_STATUS.has(status);
156
+ }
136
157
  var AgentApiTransport = class {
137
158
  apiKey;
138
159
  apiUrl;
@@ -145,16 +166,17 @@ var AgentApiTransport = class {
145
166
  * `Content-Type: application/json` and parses a `{ data: T }` envelope,
146
167
  * neither of which fits a raw-audio flow (voice TTS/STT), so those go
147
168
  * through this instead. Auth (Bearer), the request budget, and the single
148
- * retry on transient 5xx / network errors are kept in sync with
149
- * `request()`. Retries fire only on statuses produced BEFORE the route
150
- * handler runs (authorizer-timeout 500 + LB 502/503/504), so re-issuing a
151
- * POST does not risk a duplicate side effect.
169
+ * retry policy on transient 5xx / network errors is kept in sync with
170
+ * `request()`. Safe read methods retry once by default; mutation methods do
171
+ * not, because a response can be lost after a handler or provider call has
172
+ * already succeeded.
152
173
  */
153
- async rawRequest(path, init) {
174
+ async rawRequest(path, init, extra) {
154
175
  const url = `${this.apiUrl}${path}`;
155
176
  init.headers.set("Authorization", `Bearer ${this.apiKey}`);
177
+ const maxAttempts = extra?.retry ?? isSafeRetryMethod(init.method) ? 2 : 1;
156
178
  let lastError;
157
- for (let attempt = 1; attempt <= 2; attempt++) try {
179
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) try {
158
180
  const res = await fetch(url, {
159
181
  method: init.method,
160
182
  headers: init.headers,
@@ -165,7 +187,7 @@ var AgentApiTransport = class {
165
187
  const errorBody = await res.text();
166
188
  const error = new Error(formatErrorMessage(res.status, errorBody));
167
189
  error.status = res.status;
168
- if (attempt === 1 && RETRYABLE_STATUS.has(res.status)) {
190
+ if (attempt < maxAttempts && RETRYABLE_STATUS.has(res.status)) {
169
191
  lastError = error;
170
192
  await sleep(RETRY_DELAY_MS);
171
193
  continue;
@@ -174,7 +196,7 @@ var AgentApiTransport = class {
174
196
  }
175
197
  return res;
176
198
  } catch (err) {
177
- if (attempt === 1 && isRetryableNetworkError(err)) {
199
+ if (attempt < maxAttempts && isRetryableNetworkError(err)) {
178
200
  lastError = err;
179
201
  await sleep(RETRY_DELAY_MS);
180
202
  continue;
@@ -187,8 +209,11 @@ var AgentApiTransport = class {
187
209
  * @param extra.timeoutMs Per-request abort timeout (default REQUEST_TIMEOUT_MS).
188
210
  * Long endpoints (image generation) pass a larger value so the gateway's
189
211
  * own timeout wins with a readable status instead of a client-side abort.
190
- * @param extra.retry Whether to retry once on transient failures (default
191
- * true). Expensive/non-idempotent endpoints pass false.
212
+ * @param extra.retry Whether to retry once on transient failures. Safe reads
213
+ * (GET/HEAD/OPTIONS) default to true; mutations default to false. Set true
214
+ * only when the endpoint's server-side contract is explicitly idempotent.
215
+ * @param extra.signal Optional caller cancellation combined with the client's
216
+ * own timeout budget. Aborting either signal cancels the request.
192
217
  */
193
218
  async request(path, options, extra) {
194
219
  const url = `${this.apiUrl}${path}`;
@@ -196,13 +221,13 @@ var AgentApiTransport = class {
196
221
  headers.set("Authorization", `Bearer ${this.apiKey}`);
197
222
  headers.set("Content-Type", "application/json");
198
223
  const timeoutMs = extra?.timeoutMs ?? 2e4;
199
- const maxAttempts = extra?.retry === false ? 1 : 2;
224
+ const maxAttempts = extra?.retry ?? isSafeRetryMethod(options?.method) ? 2 : 1;
200
225
  let lastError;
201
226
  for (let attempt = 1; attempt <= maxAttempts; attempt++) try {
202
227
  const res = await fetch(url, {
203
228
  ...options,
204
229
  headers,
205
- signal: AbortSignal.timeout(timeoutMs)
230
+ signal: extra?.signal ? AbortSignal.any([extra.signal, AbortSignal.timeout(timeoutMs)]) : AbortSignal.timeout(timeoutMs)
206
231
  });
207
232
  if (!res.ok) {
208
233
  const errorBody = await res.text();
@@ -371,8 +396,9 @@ var ConnectCredentialsApi = class extends ApiBase {
371
396
  * selector arg (e.g. `xeroTenantId`) on every credential-touching tool
372
397
  * and look up the matching account by that selector at dispatch time.
373
398
  *
374
- * Returned `accounts[i].accountIdentifier` is the Xero tenantId the
375
- * stable cross-session identifier the LLM should pass.
399
+ * `xeroTenantId` is the model-facing organisation selector. The separate
400
+ * `accountIdentifier` is the Connect persistence key used for refresh and
401
+ * may be an email; never substitute one for the other.
376
402
  */
377
403
  async getXeroAccounts() {
378
404
  return { accounts: (await this.transport.request("/agent/connect/xero/accounts")).accounts.map((a) => ({
@@ -382,21 +408,21 @@ var ConnectCredentialsApi = class extends ApiBase {
382
408
  connectedAt: a.connectedAt,
383
409
  accessToken: a.accessToken,
384
410
  accessTokenExpiresAt: a.accessTokenExpiresAt ?? "",
385
- xeroTenantId: a.xeroTenantId ?? a.accountIdentifier
411
+ xeroTenantId: a.xeroTenantId ?? ""
386
412
  })) };
387
413
  }
388
414
  async refreshXeroToken() {
389
- return this.transport.request("/agent/connect/xero/refresh", { method: "POST" });
415
+ return this.transport.request("/agent/connect/xero/refresh", { method: "POST" }, { retry: true });
390
416
  }
391
417
  /**
392
- * Pattern A: refresh a specific Xero connection by its `accountIdentifier`
393
- * (the Xero `tenantId`). The legacy `refreshXeroToken()` only refreshes
394
- * the *primary* connection, which is wrong for multi-tenant Xero where
395
- * each tenant has its own non-interchangeable access token.
418
+ * Refresh a specific Xero Connection by its exact `accountIdentifier` from
419
+ * `getXeroAccounts()`. Do not substitute `xeroTenantId`: current Xero OAuth
420
+ * rows may use the account email as their persistence key even when a sole
421
+ * organisation tenant ID is available in provider metadata.
396
422
  */
397
- async refreshXeroAccountToken(xeroTenantId) {
398
- const path = `/agent/connect/xero/accounts/${encodeURIComponent(xeroTenantId)}/refresh`;
399
- const raw = await this.transport.request(path, { method: "POST" });
423
+ async refreshXeroAccountToken(accountIdentifier) {
424
+ const path = `/agent/connect/xero/accounts/${encodeURIComponent(accountIdentifier)}/refresh`;
425
+ const raw = await this.transport.request(path, { method: "POST" }, { retry: true });
400
426
  return {
401
427
  accessToken: raw.accessToken,
402
428
  accessTokenExpiresAt: raw.accessTokenExpiresAt ?? "",
@@ -458,7 +484,7 @@ var ConnectCredentialsApi = class extends ApiBase {
458
484
  };
459
485
  }
460
486
  async refreshAtlassianToken() {
461
- return this.transport.request("/agent/connect/atlassian/refresh", { method: "POST" });
487
+ return this.transport.request("/agent/connect/atlassian/refresh", { method: "POST" }, { retry: true });
462
488
  }
463
489
  /**
464
490
  * Pattern A: multi-account / multi-site credential fetch for Atlassian.
@@ -514,7 +540,7 @@ var ConnectCredentialsApi = class extends ApiBase {
514
540
  */
515
541
  async refreshAtlassianAccountToken(accountIdentifier) {
516
542
  const path = `/agent/connect/atlassian/accounts/${encodeURIComponent(accountIdentifier)}/refresh`;
517
- const raw = await this.transport.request(path, { method: "POST" });
543
+ const raw = await this.transport.request(path, { method: "POST" }, { retry: true });
518
544
  return {
519
545
  accessToken: raw.accessToken,
520
546
  accessTokenExpiresAt: raw.accessTokenExpiresAt ?? "",
@@ -556,7 +582,26 @@ var ConnectCredentialsApi = class extends ApiBase {
556
582
  })) };
557
583
  }
558
584
  async refreshMYOBToken() {
559
- return this.transport.request("/agent/connect/myob/refresh", { method: "POST" });
585
+ return this.transport.request("/agent/connect/myob/refresh", { method: "POST" }, { retry: true });
586
+ }
587
+ /**
588
+ * Pattern A: refresh one MYOB Connection by its stable
589
+ * `accountIdentifier` (the MYOB business id returned by
590
+ * `getMYOBAccounts()`).
591
+ *
592
+ * MYOB refresh tokens belong to individual Connection rows. A
593
+ * multi-business client must use this method instead of refreshing the
594
+ * primary Connection and copying that access token into every cached
595
+ * business client.
596
+ */
597
+ async refreshMYOBAccountToken(accountIdentifier) {
598
+ const path = `/agent/connect/myob/accounts/${encodeURIComponent(accountIdentifier)}/refresh`;
599
+ const raw = await this.transport.request(path, { method: "POST" }, { retry: true });
600
+ return {
601
+ accessToken: raw.accessToken,
602
+ accessTokenExpiresAt: raw.accessTokenExpiresAt ?? "",
603
+ expiresAt: raw.expiresAt ?? ""
604
+ };
560
605
  }
561
606
  /**
562
607
  * @deprecated Returns a single primary credential blob. Use
@@ -597,7 +642,7 @@ var ConnectCredentialsApi = class extends ApiBase {
597
642
  */
598
643
  async refreshSalesforceAccountToken(orgId) {
599
644
  const path = `/agent/connect/salesforce/accounts/${encodeURIComponent(orgId)}/refresh`;
600
- const raw = await this.transport.request(path, { method: "POST" });
645
+ const raw = await this.transport.request(path, { method: "POST" }, { retry: true });
601
646
  return {
602
647
  accessToken: raw.accessToken,
603
648
  accessTokenExpiresAt: raw.accessTokenExpiresAt ?? "",
@@ -627,9 +672,6 @@ var ConnectCredentialsApi = class extends ApiBase {
627
672
  connectedAt: a.connectedAt,
628
673
  accessToken: a.accessToken ?? "",
629
674
  accessTokenExpiresAt: a.accessTokenExpiresAt ?? "",
630
- refreshToken: a.refreshToken ?? "",
631
- clientId: a.clientId ?? "",
632
- clientSecret: a.clientSecret ?? "",
633
675
  email: a.email ?? a.accountIdentifier,
634
676
  microsoftTenantId: a.microsoftTenantId ?? "",
635
677
  workspaceDomain: a.workspaceDomain ?? ""
@@ -651,7 +693,7 @@ var ConnectCredentialsApi = class extends ApiBase {
651
693
  */
652
694
  async refreshMicrosoftAccountToken(accountIdentifier) {
653
695
  const path = `/agent/connect/microsoft/accounts/${encodeURIComponent(accountIdentifier)}/refresh`;
654
- const raw = await this.transport.request(path, { method: "POST" });
696
+ const raw = await this.transport.request(path, { method: "POST" }, { retry: true });
655
697
  return {
656
698
  accessToken: raw.accessToken,
657
699
  accessTokenExpiresAt: raw.accessTokenExpiresAt ?? "",
@@ -875,7 +917,7 @@ var ConnectCredentialsApi = class extends ApiBase {
875
917
  */
876
918
  async refreshSocialAccount(provider, accountIdentifier) {
877
919
  const path = `/agent/connect/${encodeURIComponent(provider)}/accounts/${encodeURIComponent(accountIdentifier)}/refresh`;
878
- const raw = await this.transport.request(path, { method: "POST" });
920
+ const raw = await this.transport.request(path, { method: "POST" }, { retry: true });
879
921
  return {
880
922
  accountIdentifier: raw.accountIdentifier,
881
923
  accessToken: raw.accessToken,
@@ -941,11 +983,8 @@ var IdentityApi = class extends ApiBase {
941
983
  body: JSON.stringify(args)
942
984
  });
943
985
  }
944
- async unmergeIdentity(identityId, args) {
945
- return this.transport.request(`/agent/identity/${encodeURIComponent(identityId)}/unmerge`, {
946
- method: "POST",
947
- body: JSON.stringify(args)
948
- });
986
+ async unmergeIdentity(identityId) {
987
+ return this.transport.request(`/agent/identity/${encodeURIComponent(identityId)}/unmerge`, { method: "POST" });
949
988
  }
950
989
  async addIdentityNote(identityId, args) {
951
990
  return this.transport.request(`/agent/identity/${encodeURIComponent(identityId)}/notes`, {
@@ -962,6 +1001,7 @@ var IdentityApi = class extends ApiBase {
962
1001
  async getIdentityChangelog(identityId, args) {
963
1002
  const qs = new URLSearchParams();
964
1003
  if (args?.limit) qs.set("limit", String(args.limit));
1004
+ if (args?.cursor) qs.set("cursor", args.cursor);
965
1005
  const query = qs.toString();
966
1006
  return this.transport.request(`/agent/identity/${encodeURIComponent(identityId)}/changelog${query ? `?${query}` : ""}`);
967
1007
  }
@@ -1038,8 +1078,9 @@ var ImagesApi = class extends ApiBase {
1038
1078
  let job;
1039
1079
  try {
1040
1080
  job = await this.transport.request(`/agent/images/${jobId}`);
1041
- } catch {
1042
- continue;
1081
+ } catch (error) {
1082
+ if (isTransientRequestError(error)) continue;
1083
+ throw error;
1043
1084
  }
1044
1085
  if (job.status === "completed") {
1045
1086
  if (!job.imageUrl) throw new Error("Image generation completed without a URL");
@@ -1112,6 +1153,8 @@ var IntegrationsApi = class extends ApiBase {
1112
1153
  * Knowledge resource methods (org/team/project scoped docs, profiles,
1113
1154
  * change requests + RAG search) for the Agent API client.
1114
1155
  */
1156
+ /** Matches services/knowledge's maximum indexed document size. */
1157
+ const MAX_KNOWLEDGE_DOCUMENT_BYTES = 2 * 1024 * 1024;
1115
1158
  var KnowledgeApi = class extends ApiBase {
1116
1159
  /**
1117
1160
  * Semantic search across the agent's member scopes. Fan-out is gated
@@ -1200,16 +1243,18 @@ var KnowledgeApi = class extends ApiBase {
1200
1243
  * from `services/org`, then fetches the bytes directly from S3 (the one
1201
1244
  * legitimate raw fetch in a plugin — same pattern as sync).
1202
1245
  */
1203
- async readScopeDoc(scopeType, scopeId, filePath) {
1246
+ async readScopeDoc(scopeType, scopeId, filePath, opts) {
1247
+ const maxBytes = opts?.maxBytes ?? 2097152;
1248
+ if (!Number.isInteger(maxBytes) || maxBytes < 1 || maxBytes > 2097152) throw new RangeError(`maxBytes must be an integer from 1 to ${String(MAX_KNOWLEDGE_DOCUMENT_BYTES)}`);
1204
1249
  const { downloadUrl } = await this.transport.request(`/agent/org/files/${encodeURIComponent(scopeType)}/${encodeURIComponent(scopeId)}/download/${encodeFilePath(filePath)}`);
1205
1250
  const res = await fetch(downloadUrl, { signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS) });
1206
1251
  if (!res.ok) {
1207
- await res.text();
1252
+ await res.body?.cancel().catch(() => void 0);
1208
1253
  throw new Error(`Doc download failed (${String(res.status)})`);
1209
1254
  }
1210
1255
  return {
1211
1256
  filePath,
1212
- text: await res.text()
1257
+ text: await readBoundedUtf8(res, maxBytes)
1213
1258
  };
1214
1259
  }
1215
1260
  /**
@@ -1243,6 +1288,52 @@ var KnowledgeApi = class extends ApiBase {
1243
1288
  return { filePath: presign.filePath };
1244
1289
  }
1245
1290
  };
1291
+ async function readBoundedUtf8(response, maxBytes) {
1292
+ const declaredLength = response.headers.get("content-length");
1293
+ if (declaredLength !== null && /^\d+$/u.test(declaredLength) && Number(declaredLength) > maxBytes) {
1294
+ await response.body?.cancel().catch(() => void 0);
1295
+ throw documentTooLargeError(maxBytes);
1296
+ }
1297
+ if (response.body === null) return "";
1298
+ const reader = response.body.getReader();
1299
+ const chunks = [];
1300
+ let total = 0;
1301
+ let complete = false;
1302
+ try {
1303
+ while (!complete) {
1304
+ const { done, value } = await reader.read();
1305
+ if (done) {
1306
+ complete = true;
1307
+ continue;
1308
+ }
1309
+ total += value.byteLength;
1310
+ if (total > maxBytes) {
1311
+ await reader.cancel().catch(() => void 0);
1312
+ throw documentTooLargeError(maxBytes);
1313
+ }
1314
+ chunks.push(value);
1315
+ }
1316
+ } finally {
1317
+ reader.releaseLock();
1318
+ }
1319
+ const bytes = new Uint8Array(total);
1320
+ let offset = 0;
1321
+ for (const chunk of chunks) {
1322
+ bytes.set(chunk, offset);
1323
+ offset += chunk.byteLength;
1324
+ }
1325
+ try {
1326
+ return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
1327
+ } catch {
1328
+ throw new Error("Knowledge document is not valid UTF-8 text");
1329
+ }
1330
+ }
1331
+ function documentTooLargeError(maxBytes) {
1332
+ const error = /* @__PURE__ */ new Error(`Knowledge document exceeds the ${String(maxBytes)} byte read limit`);
1333
+ error.name = "KnowledgeDocumentTooLargeError";
1334
+ error.code = "KNOWLEDGE_DOCUMENT_TOO_LARGE";
1335
+ return error;
1336
+ }
1246
1337
  //#endregion
1247
1338
  //#region src/domains/memory.ts
1248
1339
  /**
@@ -1417,23 +1508,23 @@ var RemoteApi = class extends ApiBase {
1417
1508
  * Web/image/news search methods (services/search) for the Agent API client.
1418
1509
  */
1419
1510
  var SearchApi = class extends ApiBase {
1420
- async searchWeb(params) {
1511
+ async searchWeb(params, options) {
1421
1512
  return this.transport.request("/agent/search/web", {
1422
1513
  method: "POST",
1423
1514
  body: JSON.stringify(params)
1424
- });
1515
+ }, { signal: options?.signal });
1425
1516
  }
1426
- async searchImages(params) {
1517
+ async searchImages(params, options) {
1427
1518
  return this.transport.request("/agent/search/images", {
1428
1519
  method: "POST",
1429
1520
  body: JSON.stringify(params)
1430
- });
1521
+ }, { signal: options?.signal });
1431
1522
  }
1432
- async searchNews(params) {
1523
+ async searchNews(params, options) {
1433
1524
  return this.transport.request("/agent/search/news", {
1434
1525
  method: "POST",
1435
1526
  body: JSON.stringify(params)
1436
- });
1527
+ }, { signal: options?.signal });
1437
1528
  }
1438
1529
  /** Search news across the selected provider's corpus. → POST /agent/news/search */
1439
1530
  async newsSearch(params) {
@@ -1584,8 +1675,9 @@ var SelfApi = class extends ApiBase {
1584
1675
  let job;
1585
1676
  try {
1586
1677
  job = await this.transport.request(`/agent/avatar/${jobId}`);
1587
- } catch {
1588
- continue;
1678
+ } catch (error) {
1679
+ if (isTransientRequestError(error)) continue;
1680
+ throw error;
1589
1681
  }
1590
1682
  if (job.status === "completed") {
1591
1683
  if (!job.agent) throw new Error("Avatar generation completed without an agent");
@@ -1730,7 +1822,11 @@ var SyncApi = class extends ApiBase {
1730
1822
  return this.transport.request(`/agent/sync/files/${encodeFilePath(filePath)}`, { method: "DELETE" });
1731
1823
  }
1732
1824
  async sharedListFiles(args) {
1733
- return this.transport.request(`/agent/org/files/${encodeURIComponent(args.scope)}/${encodeURIComponent(args.scopeId)}`);
1825
+ const params = new URLSearchParams();
1826
+ if (args.limit !== void 0) params.set("limit", String(args.limit));
1827
+ if (args.cursor) params.set("cursor", args.cursor);
1828
+ const query = params.toString();
1829
+ return this.transport.request(`/agent/org/files/${encodeURIComponent(args.scope)}/${encodeURIComponent(args.scopeId)}${query ? `?${query}` : ""}`);
1734
1830
  }
1735
1831
  async sharedDownloadUrl(args) {
1736
1832
  return this.transport.request(`/agent/org/files/${encodeURIComponent(args.scope)}/${encodeURIComponent(args.scopeId)}/download/${encodeFilePath(args.filePath)}`);
@@ -1763,11 +1859,11 @@ var TeamsApi = class extends ApiBase {
1763
1859
  */
1764
1860
  var WorkspaceApi = class extends ApiBase {
1765
1861
  /**
1766
- * GET /agents/me/workspace — workspace config for the authenticated agent
1862
+ * GET /agent/workspace — workspace config for the authenticated agent
1767
1863
  * (template assignment, default model, org roster).
1768
1864
  */
1769
1865
  async getWorkspace() {
1770
- return this.transport.request("/agents/me/workspace");
1866
+ return this.transport.request("/agent/workspace");
1771
1867
  }
1772
1868
  /**
1773
1869
  * GET /templates/{key}/files — persona/workspace file contents for a
@@ -1776,7 +1872,30 @@ var WorkspaceApi = class extends ApiBase {
1776
1872
  */
1777
1873
  async getTemplateFiles(templateKey, opts) {
1778
1874
  const query = opts?.version !== void 0 ? `?version=${String(opts.version)}` : "";
1779
- return this.transport.request(`/templates/${encodeURIComponent(templateKey)}/files${query}`);
1875
+ return this.transport.request(`/agent/templates/${encodeURIComponent(templateKey)}/files${query}`);
1876
+ }
1877
+ };
1878
+ //#endregion
1879
+ //#region src/domains/webhooks.ts
1880
+ /** Agent self-service webhook management methods. */
1881
+ var WebhooksApi = class extends ApiBase {
1882
+ async createWebhook(args) {
1883
+ return this.transport.request("/agent/webhooks", {
1884
+ method: "POST",
1885
+ body: JSON.stringify(args)
1886
+ }, { retry: false });
1887
+ }
1888
+ async listWebhooks() {
1889
+ return (await this.transport.request("/agent/webhooks")).webhooks;
1890
+ }
1891
+ async deleteWebhook(webhookId) {
1892
+ return this.transport.request(`/agent/webhooks/${encodeURIComponent(webhookId)}`, { method: "DELETE" });
1893
+ }
1894
+ async rotateWebhookSecret(webhookId) {
1895
+ return this.transport.request(`/agent/webhooks/${encodeURIComponent(webhookId)}/rotate`, { method: "POST" }, { retry: false });
1896
+ }
1897
+ async listWebhookDeliveries(webhookId) {
1898
+ return (await this.transport.request(`/agent/webhooks/${encodeURIComponent(webhookId)}/deliveries`)).deliveries;
1780
1899
  }
1781
1900
  };
1782
1901
  //#endregion
@@ -1811,7 +1930,8 @@ applyMixins(AgentApiClient, [
1811
1930
  RemoteApi,
1812
1931
  SelfApi,
1813
1932
  VoiceApi,
1814
- ImagesApi
1933
+ ImagesApi,
1934
+ WebhooksApi
1815
1935
  ]);
1816
1936
  //#endregion
1817
1937
  exports.AgentApiClient = AgentApiClient;