@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 +23 -1
- package/dist/index.cjs +182 -62
- package/dist/index.d.cts +113 -56
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +113 -56
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +182 -62
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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
|
-
|
|
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
|
-
|
|
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)
|
|
82
|
+
if (typeof tool === "object" && tool !== null) try {
|
|
83
|
+
wrapExecute(tool, opts);
|
|
84
|
+
} catch {}
|
|
76
85
|
return tool;
|
|
77
86
|
};
|
|
78
|
-
|
|
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
|
-
|
|
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
|
|
148
|
-
* `request()`.
|
|
149
|
-
*
|
|
150
|
-
*
|
|
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 <=
|
|
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
|
|
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
|
|
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
|
|
190
|
-
*
|
|
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
|
|
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
|
-
*
|
|
374
|
-
*
|
|
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 ??
|
|
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
|
-
*
|
|
392
|
-
* (
|
|
393
|
-
* the
|
|
394
|
-
*
|
|
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(
|
|
397
|
-
const path = `/agent/connect/xero/accounts/${encodeURIComponent(
|
|
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
|
|
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.
|
|
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
|
|
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
|
-
|
|
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 /
|
|
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("/
|
|
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 };
|