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