@agents24/client 0.1.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/LICENSE +21 -0
- package/README.md +47 -0
- package/compatibility.json +54 -0
- package/dist/adapters/browser.d.ts +3 -0
- package/dist/adapters/browser.js +12 -0
- package/dist/adapters/browser.js.map +1 -0
- package/dist/adapters/cloudflare.d.ts +3 -0
- package/dist/adapters/cloudflare.js +12 -0
- package/dist/adapters/cloudflare.js.map +1 -0
- package/dist/adapters/node.d.ts +3 -0
- package/dist/adapters/node.js +12 -0
- package/dist/adapters/node.js.map +1 -0
- package/dist/adapters/worker.d.ts +3 -0
- package/dist/adapters/worker.js +12 -0
- package/dist/adapters/worker.js.map +1 -0
- package/dist/base64url.d.ts +2 -0
- package/dist/capabilities.d.ts +7 -0
- package/dist/chunk-45ITVMX3.js +977 -0
- package/dist/chunk-45ITVMX3.js.map +1 -0
- package/dist/chunk-VVLMMNXI.js +163 -0
- package/dist/chunk-VVLMMNXI.js.map +1 -0
- package/dist/client.d.ts +2 -0
- package/dist/context-window.d.ts +44 -0
- package/dist/dpop.d.ts +43 -0
- package/dist/errors.d.ts +27 -0
- package/dist/generated/protocol.d.ts +70 -0
- package/dist/http.d.ts +38 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +557 -0
- package/dist/index.js.map +1 -0
- package/dist/multipart.d.ts +2 -0
- package/dist/protocol.d.ts +5 -0
- package/dist/protocol.js +146 -0
- package/dist/protocol.js.map +1 -0
- package/dist/runtime-types.d.ts +93 -0
- package/dist/sessions.d.ts +63 -0
- package/dist/stream.d.ts +20 -0
- package/dist/types.d.ts +367 -0
- package/dist/url.d.ts +5 -0
- package/package.json +88 -0
|
@@ -0,0 +1,977 @@
|
|
|
1
|
+
import { createSseParser, Agents24ProtocolError, parseRuntimeSsePayload, parseThreadSummarySsePayload } from './chunk-VVLMMNXI.js';
|
|
2
|
+
|
|
3
|
+
// src/errors.ts
|
|
4
|
+
var Agents24ClientError = class extends Error {
|
|
5
|
+
kind;
|
|
6
|
+
code;
|
|
7
|
+
status;
|
|
8
|
+
requestId;
|
|
9
|
+
retryable;
|
|
10
|
+
cause;
|
|
11
|
+
constructor(message, options) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = "Agents24ClientError";
|
|
14
|
+
this.kind = options.kind;
|
|
15
|
+
this.code = options.code ?? "CLIENT_ERROR";
|
|
16
|
+
this.status = options.status;
|
|
17
|
+
this.requestId = options.requestId;
|
|
18
|
+
this.retryable = options.retryable ?? false;
|
|
19
|
+
this.cause = options.cause;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
function missingCapability(name) {
|
|
23
|
+
return new Agents24ClientError(`Required capability is unavailable: ${name}.`, {
|
|
24
|
+
kind: "missing_capability",
|
|
25
|
+
code: "MISSING_CAPABILITY"
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function errorKindForStatus(status) {
|
|
29
|
+
if (status === 401) return "authentication";
|
|
30
|
+
if (status === 403) return "authorization";
|
|
31
|
+
if (status === 404) return "not_found";
|
|
32
|
+
if (status === 409) return "conflict";
|
|
33
|
+
if (status === 422 || status === 400) return "validation";
|
|
34
|
+
if (status === 429) return "rate_limit";
|
|
35
|
+
return "server";
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// src/capabilities.ts
|
|
39
|
+
function globals() {
|
|
40
|
+
return globalThis;
|
|
41
|
+
}
|
|
42
|
+
function resolveFetch(injected) {
|
|
43
|
+
if (injected) return injected;
|
|
44
|
+
const implementation = globals().fetch;
|
|
45
|
+
if (!implementation) throw missingCapability("fetch");
|
|
46
|
+
return implementation.bind(globalThis);
|
|
47
|
+
}
|
|
48
|
+
function resolveDecoderFactory(injected) {
|
|
49
|
+
if (injected) return injected;
|
|
50
|
+
const Constructor = globals().TextDecoder;
|
|
51
|
+
if (!Constructor) throw missingCapability("TextDecoder");
|
|
52
|
+
return () => new Constructor("utf-8", { fatal: true });
|
|
53
|
+
}
|
|
54
|
+
function resolveEncoder(injected) {
|
|
55
|
+
if (injected) return injected;
|
|
56
|
+
const Constructor = globals().TextEncoder;
|
|
57
|
+
if (!Constructor) throw missingCapability("TextEncoder");
|
|
58
|
+
return new Constructor();
|
|
59
|
+
}
|
|
60
|
+
function defaultClock() {
|
|
61
|
+
return { now: () => Date.now() };
|
|
62
|
+
}
|
|
63
|
+
function randomHex(bytes) {
|
|
64
|
+
const target = new Uint8Array(bytes);
|
|
65
|
+
const crypto = globals().crypto;
|
|
66
|
+
const getRandomValues = crypto?.getRandomValues?.bind(crypto);
|
|
67
|
+
if (!getRandomValues) throw missingCapability("crypto.getRandomValues");
|
|
68
|
+
getRandomValues(target);
|
|
69
|
+
return Array.from(target, (value) => value.toString(16).padStart(2, "0")).join("");
|
|
70
|
+
}
|
|
71
|
+
function defaultIds() {
|
|
72
|
+
return {
|
|
73
|
+
createId() {
|
|
74
|
+
const crypto = globals().crypto;
|
|
75
|
+
const randomUUID = crypto?.randomUUID?.bind(crypto);
|
|
76
|
+
return randomUUID ? randomUUID() : randomHex(16);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function secureRandomBytes(length) {
|
|
81
|
+
const target = new Uint8Array(length);
|
|
82
|
+
const crypto = globals().crypto;
|
|
83
|
+
const getRandomValues = crypto?.getRandomValues?.bind(crypto);
|
|
84
|
+
if (!getRandomValues) throw missingCapability("crypto.getRandomValues");
|
|
85
|
+
return getRandomValues(target);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// src/multipart.ts
|
|
89
|
+
function isBlobLike(value) {
|
|
90
|
+
return typeof value.arrayBuffer === "function";
|
|
91
|
+
}
|
|
92
|
+
async function toBytes(value) {
|
|
93
|
+
if (value instanceof Uint8Array) return value;
|
|
94
|
+
if (value instanceof ArrayBuffer) return new Uint8Array(value);
|
|
95
|
+
if (isBlobLike(value)) return new Uint8Array(await value.arrayBuffer());
|
|
96
|
+
throw new Agents24ClientError("Upload data must be bytes, an ArrayBuffer, or a compatible blob-like value.", {
|
|
97
|
+
kind: "validation",
|
|
98
|
+
code: "INVALID_UPLOAD_DATA"
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
function safeToken(value, field) {
|
|
102
|
+
if (!value || /[\r\n\0]/.test(value)) {
|
|
103
|
+
throw new Agents24ClientError(`${field} contains invalid characters.`, {
|
|
104
|
+
kind: "validation",
|
|
105
|
+
code: "INVALID_MULTIPART_METADATA"
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
return value.replace(/["\\]/g, "_");
|
|
109
|
+
}
|
|
110
|
+
function concat(chunks) {
|
|
111
|
+
const length = chunks.reduce((total, chunk) => total + chunk.byteLength, 0);
|
|
112
|
+
const output = new Uint8Array(length);
|
|
113
|
+
let offset = 0;
|
|
114
|
+
for (const chunk of chunks) {
|
|
115
|
+
output.set(chunk, offset);
|
|
116
|
+
offset += chunk.byteLength;
|
|
117
|
+
}
|
|
118
|
+
return output;
|
|
119
|
+
}
|
|
120
|
+
async function encodePart(part, boundary, encoder) {
|
|
121
|
+
const field = safeToken(part.field, "Multipart field");
|
|
122
|
+
if (typeof part.value === "string") {
|
|
123
|
+
return [encoder.encode(`--${boundary}\r
|
|
124
|
+
Content-Disposition: form-data; name="${field}"\r
|
|
125
|
+
\r
|
|
126
|
+
${part.value}\r
|
|
127
|
+
`)];
|
|
128
|
+
}
|
|
129
|
+
const upload = part.value;
|
|
130
|
+
const filename = safeToken(upload.name, "Upload filename");
|
|
131
|
+
const mediaType = safeToken(upload.mediaType, "Upload media type");
|
|
132
|
+
return [
|
|
133
|
+
encoder.encode(
|
|
134
|
+
`--${boundary}\r
|
|
135
|
+
Content-Disposition: form-data; name="${field}"; filename="${filename}"\r
|
|
136
|
+
Content-Type: ${mediaType}\r
|
|
137
|
+
\r
|
|
138
|
+
`
|
|
139
|
+
),
|
|
140
|
+
await toBytes(upload.data),
|
|
141
|
+
encoder.encode("\r\n")
|
|
142
|
+
];
|
|
143
|
+
}
|
|
144
|
+
function createByteMultipartEncoder(encoder) {
|
|
145
|
+
return {
|
|
146
|
+
async encode(parts) {
|
|
147
|
+
const boundary = `agents24-${Array.from(secureRandomBytes(18), (value) => value.toString(16).padStart(2, "0")).join("")}`;
|
|
148
|
+
const chunks = [];
|
|
149
|
+
for (const part of parts) chunks.push(...await encodePart(part, boundary, encoder));
|
|
150
|
+
chunks.push(encoder.encode(`--${boundary}--\r
|
|
151
|
+
`));
|
|
152
|
+
return {
|
|
153
|
+
body: concat(chunks),
|
|
154
|
+
contentType: `multipart/form-data; boundary=${boundary}`
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// src/url.ts
|
|
161
|
+
function urlConstructor() {
|
|
162
|
+
const Constructor = globalThis.URL;
|
|
163
|
+
if (!Constructor) throw missingCapability("URL");
|
|
164
|
+
return Constructor;
|
|
165
|
+
}
|
|
166
|
+
function normalizeBaseUrl(input) {
|
|
167
|
+
let parsed;
|
|
168
|
+
try {
|
|
169
|
+
parsed = new (urlConstructor())(input);
|
|
170
|
+
} catch (cause) {
|
|
171
|
+
throw new Agents24ClientError("baseUrl must be an absolute HTTP(S) URL.", {
|
|
172
|
+
kind: "configuration",
|
|
173
|
+
code: "INVALID_BASE_URL",
|
|
174
|
+
cause
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
if (!/^https?:$/.test(parsed.protocol) || parsed.username || parsed.password || parsed.hash) {
|
|
178
|
+
throw new Agents24ClientError("baseUrl must be an absolute HTTP(S) origin without credentials or a fragment.", {
|
|
179
|
+
kind: "configuration",
|
|
180
|
+
code: "INVALID_BASE_URL"
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
return `${parsed.origin}${parsed.pathname.replace(/\/+$/, "")}`;
|
|
184
|
+
}
|
|
185
|
+
function absoluteUrl(baseUrl, path) {
|
|
186
|
+
return new (urlConstructor())(path, `${baseUrl}/`).toString();
|
|
187
|
+
}
|
|
188
|
+
function canonicalHtu(input) {
|
|
189
|
+
const parsed = new (urlConstructor())(input);
|
|
190
|
+
parsed.hash = "";
|
|
191
|
+
return parsed.toString();
|
|
192
|
+
}
|
|
193
|
+
function encodePath(value) {
|
|
194
|
+
return encodeURIComponent(value);
|
|
195
|
+
}
|
|
196
|
+
function appendQuery(path, values) {
|
|
197
|
+
const query = Object.entries(values).filter((entry) => entry[1] !== void 0).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`).join("&");
|
|
198
|
+
return query ? `${path}?${query}` : path;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// src/http.ts
|
|
202
|
+
var RESERVED_REQUEST_HEADERS = /* @__PURE__ */ new Set([
|
|
203
|
+
"accept",
|
|
204
|
+
"authorization",
|
|
205
|
+
"cache-control",
|
|
206
|
+
"content-type",
|
|
207
|
+
"cookie",
|
|
208
|
+
"dpop",
|
|
209
|
+
"host",
|
|
210
|
+
"idempotency-key",
|
|
211
|
+
"origin",
|
|
212
|
+
"pragma",
|
|
213
|
+
"proxy-authorization"
|
|
214
|
+
]);
|
|
215
|
+
function safeToken2(value, field) {
|
|
216
|
+
if (!value || /[\r\n\0]/.test(value)) {
|
|
217
|
+
throw new Agents24ClientError(`${field} is invalid.`, {
|
|
218
|
+
kind: "configuration",
|
|
219
|
+
code: "INVALID_CREDENTIAL"
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
return value;
|
|
223
|
+
}
|
|
224
|
+
function appendAdditionalHeaders(target, additional) {
|
|
225
|
+
for (const [name, value] of Object.entries(additional ?? {})) {
|
|
226
|
+
const normalized = name.toLowerCase();
|
|
227
|
+
if (!/^[a-z0-9!#$%&'*+.^_`|~-]+$/.test(normalized) || RESERVED_REQUEST_HEADERS.has(normalized)) {
|
|
228
|
+
throw new Agents24ClientError(`Reserved or invalid request header: ${name}.`, {
|
|
229
|
+
kind: "configuration",
|
|
230
|
+
code: "RESERVED_REQUEST_HEADER"
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
target[name] = safeToken2(value, `Request header ${name}`);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
function isPublicError(value) {
|
|
237
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
238
|
+
const candidate = value;
|
|
239
|
+
return typeof candidate.code === "string" && typeof candidate.message === "string" && typeof candidate.request_id === "string" && typeof candidate.retryable === "boolean";
|
|
240
|
+
}
|
|
241
|
+
async function responseError(response) {
|
|
242
|
+
let body;
|
|
243
|
+
try {
|
|
244
|
+
body = await response.json();
|
|
245
|
+
} catch {
|
|
246
|
+
body = void 0;
|
|
247
|
+
}
|
|
248
|
+
if (isPublicError(body)) {
|
|
249
|
+
return new Agents24ClientError(body.message, {
|
|
250
|
+
kind: errorKindForStatus(response.status),
|
|
251
|
+
code: body.code,
|
|
252
|
+
status: response.status,
|
|
253
|
+
requestId: body.request_id,
|
|
254
|
+
retryable: body.retryable
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
return new Agents24ClientError("The Agents24 runtime request failed.", {
|
|
258
|
+
kind: errorKindForStatus(response.status),
|
|
259
|
+
code: `HTTP_${response.status}`,
|
|
260
|
+
status: response.status,
|
|
261
|
+
retryable: response.status >= 500
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
async function responseJson(response) {
|
|
265
|
+
try {
|
|
266
|
+
return await response.json();
|
|
267
|
+
} catch (cause) {
|
|
268
|
+
throw new Agents24ClientError("The runtime returned invalid JSON.", {
|
|
269
|
+
kind: "protocol",
|
|
270
|
+
code: "INVALID_JSON_RESPONSE",
|
|
271
|
+
cause
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
function assertPrivateResponse(response) {
|
|
276
|
+
if (response.redirected || response.status >= 300 && response.status < 400) {
|
|
277
|
+
throw new Agents24ClientError("Authenticated redirects are not allowed.", {
|
|
278
|
+
kind: "network",
|
|
279
|
+
code: "REDIRECT_REJECTED",
|
|
280
|
+
status: response.status
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
var AuthenticatedHttp = class {
|
|
285
|
+
#baseUrl;
|
|
286
|
+
#provider;
|
|
287
|
+
#fetch;
|
|
288
|
+
#clock;
|
|
289
|
+
#telemetry;
|
|
290
|
+
#nonces = /* @__PURE__ */ new Map();
|
|
291
|
+
constructor(options) {
|
|
292
|
+
this.#baseUrl = options.baseUrl;
|
|
293
|
+
this.#provider = options.sessionProvider;
|
|
294
|
+
this.#fetch = options.fetch;
|
|
295
|
+
this.#clock = options.clock ?? defaultClock();
|
|
296
|
+
this.#telemetry = options.telemetry;
|
|
297
|
+
}
|
|
298
|
+
async #emit(event) {
|
|
299
|
+
try {
|
|
300
|
+
await this.#telemetry?.emit(event);
|
|
301
|
+
} catch {
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
async #access(signal) {
|
|
305
|
+
let access = await this.#provider.getAccess({ reason: "request", ...signal ? { signal } : {} });
|
|
306
|
+
if (access.expiresAt <= this.#clock.now() + 3e4 && this.#provider.refresh) {
|
|
307
|
+
access = await this.#provider.refresh({ reason: "expired", ...signal ? { signal } : {} });
|
|
308
|
+
}
|
|
309
|
+
return access;
|
|
310
|
+
}
|
|
311
|
+
async request(method, path, options) {
|
|
312
|
+
const url = absoluteUrl(this.#baseUrl, path);
|
|
313
|
+
const startedAt = this.#clock.now();
|
|
314
|
+
let access = await this.#access(options.signal);
|
|
315
|
+
let nonceRetried = false;
|
|
316
|
+
let refreshRetried = false;
|
|
317
|
+
let retryCount = 0;
|
|
318
|
+
await this.#emit({ type: "request.started", operation: options.operation, method, retryCount });
|
|
319
|
+
while (true) {
|
|
320
|
+
const token = safeToken2(access.accessToken, "Access token");
|
|
321
|
+
if (access.tokenType === "DPoP" && !access.dpopKeyProvider) {
|
|
322
|
+
throw new Agents24ClientError("A DPoP-bound session requires a DPoP key provider.", {
|
|
323
|
+
kind: "configuration",
|
|
324
|
+
code: "MISSING_DPOP_PROVIDER"
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
const headers = {
|
|
328
|
+
Accept: options.accept ?? "application/json",
|
|
329
|
+
Authorization: `${access.tokenType} ${token}`,
|
|
330
|
+
"Cache-Control": "no-store",
|
|
331
|
+
Pragma: "no-cache"
|
|
332
|
+
};
|
|
333
|
+
appendAdditionalHeaders(headers, options.headers);
|
|
334
|
+
if (options.body !== void 0) headers["Content-Type"] = "application/json";
|
|
335
|
+
if (options.contentType) headers["Content-Type"] = options.contentType;
|
|
336
|
+
if (options.idempotencyKey) headers["Idempotency-Key"] = safeToken2(options.idempotencyKey, "Idempotency key");
|
|
337
|
+
if (access.dpopKeyProvider) {
|
|
338
|
+
headers.DPoP = await access.dpopKeyProvider.signProof({
|
|
339
|
+
method,
|
|
340
|
+
url,
|
|
341
|
+
accessToken: token,
|
|
342
|
+
nonce: this.#nonces.get(access.sessionId ?? "default") ?? access.dpopNonce
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
let response;
|
|
346
|
+
try {
|
|
347
|
+
response = await this.#fetch(url, {
|
|
348
|
+
method,
|
|
349
|
+
headers,
|
|
350
|
+
body: options.rawBody ?? (options.body === void 0 ? void 0 : JSON.stringify(options.body)),
|
|
351
|
+
...options.signal ? { signal: options.signal } : {},
|
|
352
|
+
redirect: "error",
|
|
353
|
+
cache: "no-store",
|
|
354
|
+
credentials: "omit"
|
|
355
|
+
});
|
|
356
|
+
} catch (cause) {
|
|
357
|
+
if (options.signal?.aborted) {
|
|
358
|
+
throw new Agents24ClientError("The operation was locally detached.", {
|
|
359
|
+
kind: "aborted",
|
|
360
|
+
code: "ABORTED",
|
|
361
|
+
cause
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
throw new Agents24ClientError("The Agents24 runtime could not be reached.", {
|
|
365
|
+
kind: "network",
|
|
366
|
+
code: "NETWORK_ERROR",
|
|
367
|
+
retryable: true,
|
|
368
|
+
cause
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
assertPrivateResponse(response);
|
|
372
|
+
const challengedNonce = response.headers.get("DPoP-Nonce");
|
|
373
|
+
if (response.status === 401 && challengedNonce && access.dpopKeyProvider && !nonceRetried) {
|
|
374
|
+
this.#nonces.set(access.sessionId ?? "default", safeToken2(challengedNonce, "DPoP nonce"));
|
|
375
|
+
nonceRetried = true;
|
|
376
|
+
retryCount += 1;
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
if (response.status === 401 && this.#provider.refresh && !refreshRetried) {
|
|
380
|
+
access = await this.#provider.refresh({
|
|
381
|
+
reason: "unauthorized",
|
|
382
|
+
...options.signal ? { signal: options.signal } : {}
|
|
383
|
+
});
|
|
384
|
+
refreshRetried = true;
|
|
385
|
+
nonceRetried = false;
|
|
386
|
+
retryCount += 1;
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
await this.#emit({
|
|
390
|
+
type: "request.completed",
|
|
391
|
+
operation: options.operation,
|
|
392
|
+
method,
|
|
393
|
+
status: response.status,
|
|
394
|
+
durationMs: this.#clock.now() - startedAt,
|
|
395
|
+
retryCount
|
|
396
|
+
});
|
|
397
|
+
return response;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
async json(method, path, options) {
|
|
401
|
+
const response = await this.request(method, path, options);
|
|
402
|
+
if (!response.ok) throw await responseError(response);
|
|
403
|
+
return await responseJson(response);
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
async function dpopTokenRequest(input) {
|
|
407
|
+
const method = input.method ?? "POST";
|
|
408
|
+
let nonce = input.nonce;
|
|
409
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
410
|
+
const headers = {
|
|
411
|
+
Accept: "application/json",
|
|
412
|
+
"Content-Type": "application/json",
|
|
413
|
+
"Cache-Control": "no-store",
|
|
414
|
+
Pragma: "no-cache"
|
|
415
|
+
};
|
|
416
|
+
if (input.idempotencyKey) headers["Idempotency-Key"] = safeToken2(input.idempotencyKey, "Idempotency key");
|
|
417
|
+
if (input.dpopKeyProvider && !(input.prooflessInitialRequest && attempt === 0)) {
|
|
418
|
+
headers.DPoP = await input.dpopKeyProvider.signProof({ method, url: input.url, nonce });
|
|
419
|
+
}
|
|
420
|
+
let response;
|
|
421
|
+
try {
|
|
422
|
+
response = await input.fetch(input.url, {
|
|
423
|
+
method,
|
|
424
|
+
headers,
|
|
425
|
+
body: JSON.stringify(input.body),
|
|
426
|
+
...input.signal ? { signal: input.signal } : {},
|
|
427
|
+
redirect: "error",
|
|
428
|
+
cache: "no-store",
|
|
429
|
+
credentials: "omit"
|
|
430
|
+
});
|
|
431
|
+
} catch (cause) {
|
|
432
|
+
if (input.signal?.aborted) {
|
|
433
|
+
throw new Agents24ClientError("The operation was locally detached.", {
|
|
434
|
+
kind: "aborted",
|
|
435
|
+
code: "ABORTED",
|
|
436
|
+
cause
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
throw new Agents24ClientError("The Agents24 session endpoint could not be reached.", {
|
|
440
|
+
kind: "network",
|
|
441
|
+
code: "NETWORK_ERROR",
|
|
442
|
+
retryable: true,
|
|
443
|
+
cause
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
assertPrivateResponse(response);
|
|
447
|
+
const challenge = response.headers.get("DPoP-Nonce");
|
|
448
|
+
if (response.status === 401 && challenge && input.dpopKeyProvider && attempt === 0) {
|
|
449
|
+
nonce = safeToken2(challenge, "DPoP nonce");
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
452
|
+
if (input.prooflessInitialRequest && input.dpopKeyProvider && attempt === 0 && response.ok) {
|
|
453
|
+
throw new Agents24ClientError("DPoP enrollment succeeded without the required nonce challenge.", {
|
|
454
|
+
kind: "authentication",
|
|
455
|
+
code: "DPOP_ENROLLMENT_FAILED"
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
return response;
|
|
459
|
+
}
|
|
460
|
+
throw new Agents24ClientError("DPoP enrollment failed.", {
|
|
461
|
+
kind: "authentication",
|
|
462
|
+
code: "DPOP_ENROLLMENT_FAILED"
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// src/stream.ts
|
|
467
|
+
function detachReason(event) {
|
|
468
|
+
if (event.event !== "run.detached") return void 0;
|
|
469
|
+
const reason = event.payload.reason;
|
|
470
|
+
if (reason === "token_expired" || reason === "revoked" || reason === "policy_changed") return reason;
|
|
471
|
+
return "server_detach";
|
|
472
|
+
}
|
|
473
|
+
function threadId(event) {
|
|
474
|
+
const value = event.payload.thread_id;
|
|
475
|
+
return typeof value === "string" && value ? value : void 0;
|
|
476
|
+
}
|
|
477
|
+
async function consumeBody(input) {
|
|
478
|
+
if (!input.response.ok) throw await responseError(input.response);
|
|
479
|
+
if (!input.response.body) {
|
|
480
|
+
throw new Agents24ClientError("The stream response did not include a readable body.", {
|
|
481
|
+
kind: "protocol",
|
|
482
|
+
code: "MISSING_STREAM_BODY"
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
const reader = input.response.body.getReader();
|
|
486
|
+
let locallyAborted = input.signal?.aborted ?? false;
|
|
487
|
+
const onAbort = () => {
|
|
488
|
+
locallyAborted = true;
|
|
489
|
+
void reader.cancel(input.signal?.reason).catch(() => void 0);
|
|
490
|
+
};
|
|
491
|
+
input.signal?.addEventListener("abort", onAbort, { once: true });
|
|
492
|
+
const parser = createSseParser({
|
|
493
|
+
decoder: input.decoder,
|
|
494
|
+
onPayload: input.onPayload,
|
|
495
|
+
...input.signal ? { signal: input.signal } : {}
|
|
496
|
+
});
|
|
497
|
+
try {
|
|
498
|
+
while (!locallyAborted) {
|
|
499
|
+
const chunk = await reader.read();
|
|
500
|
+
if (chunk.value) await parser.push(chunk.value);
|
|
501
|
+
if (chunk.done) break;
|
|
502
|
+
}
|
|
503
|
+
if (!locallyAborted) await parser.finish();
|
|
504
|
+
} catch (cause) {
|
|
505
|
+
if (!locallyAborted) {
|
|
506
|
+
if (cause instanceof Agents24ProtocolError) throw cause;
|
|
507
|
+
throw new Agents24ClientError("The runtime stream was interrupted.", {
|
|
508
|
+
kind: "network",
|
|
509
|
+
code: "STREAM_INTERRUPTED",
|
|
510
|
+
retryable: true,
|
|
511
|
+
cause
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
} finally {
|
|
515
|
+
input.signal?.removeEventListener("abort", onAbort);
|
|
516
|
+
reader.releaseLock?.();
|
|
517
|
+
}
|
|
518
|
+
if (locallyAborted) {
|
|
519
|
+
throw new Agents24ClientError("The runtime stream was locally detached.", {
|
|
520
|
+
kind: "aborted",
|
|
521
|
+
code: "ABORTED",
|
|
522
|
+
retryable: false
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
async function consumeRuntimeStream(input) {
|
|
527
|
+
let cursor = input.afterCursor ?? null;
|
|
528
|
+
let runId = null;
|
|
529
|
+
let resolvedThreadId = null;
|
|
530
|
+
let detached = false;
|
|
531
|
+
let terminal = false;
|
|
532
|
+
let reason;
|
|
533
|
+
await consumeBody({
|
|
534
|
+
response: input.response,
|
|
535
|
+
...input.signal ? { signal: input.signal } : {},
|
|
536
|
+
decoder: input.decoder,
|
|
537
|
+
async onPayload(payload) {
|
|
538
|
+
const event = parseRuntimeSsePayload(payload);
|
|
539
|
+
if (cursor !== null && event.seq <= cursor) return;
|
|
540
|
+
if (cursor !== null && event.seq !== cursor + 1) {
|
|
541
|
+
throw new Agents24ProtocolError("invalid_envelope", "Runtime stream sequence is not contiguous.", {
|
|
542
|
+
expected: cursor + 1,
|
|
543
|
+
received: event.seq
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
cursor = event.seq;
|
|
547
|
+
runId = event.run_id;
|
|
548
|
+
resolvedThreadId = threadId(event) ?? resolvedThreadId;
|
|
549
|
+
reason = detachReason(event);
|
|
550
|
+
detached = reason !== void 0;
|
|
551
|
+
terminal = event.event === "run.completed" || event.event === "run.failed" || event.event === "run.cancelled";
|
|
552
|
+
await input.onEvent(event);
|
|
553
|
+
input.onProgress?.({
|
|
554
|
+
runId,
|
|
555
|
+
threadId: resolvedThreadId,
|
|
556
|
+
cursor,
|
|
557
|
+
detached,
|
|
558
|
+
...reason ? { detachReason: reason } : {}
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
});
|
|
562
|
+
if (runId && !terminal && !detached && !input.signal?.aborted) {
|
|
563
|
+
throw new Agents24ClientError("The runtime stream ended before a terminal or detach event.", {
|
|
564
|
+
kind: "network",
|
|
565
|
+
code: "STREAM_ENDED_BEFORE_TERMINAL",
|
|
566
|
+
retryable: true
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
return {
|
|
570
|
+
runId,
|
|
571
|
+
threadId: resolvedThreadId,
|
|
572
|
+
cursor,
|
|
573
|
+
detached,
|
|
574
|
+
...reason ? { detachReason: reason } : {}
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
async function consumeThreadSummaryStream(input) {
|
|
578
|
+
let cursor = input.afterCursor ?? null;
|
|
579
|
+
await consumeBody({
|
|
580
|
+
response: input.response,
|
|
581
|
+
...input.signal ? { signal: input.signal } : {},
|
|
582
|
+
decoder: input.decoder,
|
|
583
|
+
async onPayload(payload) {
|
|
584
|
+
const event = parseThreadSummarySsePayload(payload);
|
|
585
|
+
if (event.event !== "snapshot_required" && cursor !== null && event.cursor <= cursor) return;
|
|
586
|
+
cursor = cursor === null ? event.cursor : Math.max(cursor, event.cursor);
|
|
587
|
+
await input.onEvent(event);
|
|
588
|
+
input.onCursor?.(cursor);
|
|
589
|
+
}
|
|
590
|
+
});
|
|
591
|
+
return cursor;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// src/client.ts
|
|
595
|
+
function objectResult(value, operation) {
|
|
596
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
597
|
+
throw new Agents24ClientError(`${operation} returned an invalid response.`, {
|
|
598
|
+
kind: "protocol",
|
|
599
|
+
code: "INVALID_JSON_RESPONSE"
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
return value;
|
|
603
|
+
}
|
|
604
|
+
function deploymentPath(deploymentId, suffix) {
|
|
605
|
+
return `/public/client-runtime/deployments/${encodePath(deploymentId)}${suffix}`;
|
|
606
|
+
}
|
|
607
|
+
function shouldReconnect(error) {
|
|
608
|
+
return error instanceof Agents24ClientError && error.kind === "network" && error.retryable;
|
|
609
|
+
}
|
|
610
|
+
function createAgents24Client(options) {
|
|
611
|
+
if (!options.deploymentId || /[\r\n\0/]/.test(options.deploymentId)) {
|
|
612
|
+
throw new Agents24ClientError("deploymentId is invalid.", {
|
|
613
|
+
kind: "configuration",
|
|
614
|
+
code: "INVALID_DEPLOYMENT_ID"
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
if (options.transport !== void 0 && options.transport !== "auto" && options.transport !== "fetch") {
|
|
618
|
+
throw new Agents24ClientError("The requested transport is unavailable.", {
|
|
619
|
+
kind: "missing_capability",
|
|
620
|
+
code: "MISSING_TRANSPORT"
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
const baseUrl = normalizeBaseUrl(options.baseUrl);
|
|
624
|
+
const fetch = resolveFetch(options.fetch);
|
|
625
|
+
const decoder = resolveDecoderFactory(options.decoder);
|
|
626
|
+
const clock = options.clock ?? defaultClock();
|
|
627
|
+
const ids = options.ids ?? defaultIds();
|
|
628
|
+
const maxReconnectAttempts = Math.max(0, Math.min(options.maxReconnectAttempts ?? 3, 10));
|
|
629
|
+
const http = new AuthenticatedHttp({
|
|
630
|
+
baseUrl,
|
|
631
|
+
sessionProvider: options.sessionProvider,
|
|
632
|
+
fetch,
|
|
633
|
+
clock,
|
|
634
|
+
...options.telemetry ? { telemetry: options.telemetry } : {}
|
|
635
|
+
});
|
|
636
|
+
const emit = async (event) => {
|
|
637
|
+
try {
|
|
638
|
+
await options.telemetry?.emit(event);
|
|
639
|
+
} catch {
|
|
640
|
+
}
|
|
641
|
+
};
|
|
642
|
+
const attach = async (runId, cursor, headers, signal, onEvent, onProgress) => {
|
|
643
|
+
const response = await http.request(
|
|
644
|
+
"POST",
|
|
645
|
+
deploymentPath(options.deploymentId, `/runs/${encodePath(runId)}/attach`),
|
|
646
|
+
{
|
|
647
|
+
operation: "runs.attach",
|
|
648
|
+
accept: "text/event-stream",
|
|
649
|
+
body: cursor === void 0 ? {} : { cursor },
|
|
650
|
+
...headers ? { headers } : {},
|
|
651
|
+
...signal ? { signal } : {}
|
|
652
|
+
}
|
|
653
|
+
);
|
|
654
|
+
return consumeRuntimeStream({
|
|
655
|
+
response,
|
|
656
|
+
decoder: decoder(),
|
|
657
|
+
onEvent,
|
|
658
|
+
...signal ? { signal } : {},
|
|
659
|
+
...cursor === void 0 ? {} : { afterCursor: cursor },
|
|
660
|
+
...onProgress ? { onProgress } : {}
|
|
661
|
+
});
|
|
662
|
+
};
|
|
663
|
+
const reconnect = async (initial, signal, onEvent, operation, headers) => {
|
|
664
|
+
let state;
|
|
665
|
+
let attempt = 0;
|
|
666
|
+
const onProgress = (next) => {
|
|
667
|
+
if (!state) {
|
|
668
|
+
void emit({
|
|
669
|
+
type: "stream.connected",
|
|
670
|
+
operation,
|
|
671
|
+
...next.runId ? { runId: next.runId } : {},
|
|
672
|
+
...next.cursor === null ? {} : { cursor: next.cursor },
|
|
673
|
+
attempt
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
state = next;
|
|
677
|
+
};
|
|
678
|
+
while (true) {
|
|
679
|
+
try {
|
|
680
|
+
state = state?.runId ? await attach(state.runId, state.cursor ?? void 0, headers, signal, onEvent, onProgress) : await initial(onProgress);
|
|
681
|
+
} catch (error) {
|
|
682
|
+
if (signal?.aborted || !shouldReconnect(error) || attempt >= maxReconnectAttempts) throw error;
|
|
683
|
+
attempt += 1;
|
|
684
|
+
await emit({
|
|
685
|
+
type: "stream.reconnecting",
|
|
686
|
+
operation,
|
|
687
|
+
...state?.runId ? { runId: state.runId } : {},
|
|
688
|
+
...state?.cursor == null ? {} : { cursor: state.cursor },
|
|
689
|
+
attempt,
|
|
690
|
+
reason: "network"
|
|
691
|
+
});
|
|
692
|
+
continue;
|
|
693
|
+
}
|
|
694
|
+
if (!state.detached || signal?.aborted) {
|
|
695
|
+
await emit({
|
|
696
|
+
type: "stream.completed",
|
|
697
|
+
operation,
|
|
698
|
+
...state.runId ? { runId: state.runId } : {},
|
|
699
|
+
...state.cursor === null ? {} : { cursor: state.cursor },
|
|
700
|
+
attempt
|
|
701
|
+
});
|
|
702
|
+
return state;
|
|
703
|
+
}
|
|
704
|
+
await emit({
|
|
705
|
+
type: "stream.detached",
|
|
706
|
+
operation,
|
|
707
|
+
...state.runId ? { runId: state.runId } : {},
|
|
708
|
+
...state.cursor === null ? {} : { cursor: state.cursor },
|
|
709
|
+
attempt,
|
|
710
|
+
reason: state.detachReason ?? "server_detach"
|
|
711
|
+
});
|
|
712
|
+
if (attempt >= maxReconnectAttempts || state.detachReason === "revoked" || state.detachReason === "policy_changed") {
|
|
713
|
+
return state;
|
|
714
|
+
}
|
|
715
|
+
if (state.detachReason === "token_expired" && options.sessionProvider.refresh) {
|
|
716
|
+
await options.sessionProvider.refresh({ reason: "stream_detached", ...signal ? { signal } : {} });
|
|
717
|
+
}
|
|
718
|
+
attempt += 1;
|
|
719
|
+
}
|
|
720
|
+
};
|
|
721
|
+
return {
|
|
722
|
+
async bootstrap(input) {
|
|
723
|
+
let response;
|
|
724
|
+
try {
|
|
725
|
+
response = await fetch(
|
|
726
|
+
`${baseUrl}${deploymentPath(options.deploymentId, "/bootstrap")}`,
|
|
727
|
+
{
|
|
728
|
+
method: "GET",
|
|
729
|
+
headers: { Accept: "application/json", "Cache-Control": "no-store", Pragma: "no-cache" },
|
|
730
|
+
redirect: "error",
|
|
731
|
+
cache: "no-store",
|
|
732
|
+
credentials: "omit",
|
|
733
|
+
...input?.signal ? { signal: input.signal } : {}
|
|
734
|
+
}
|
|
735
|
+
);
|
|
736
|
+
} catch (cause) {
|
|
737
|
+
throw new Agents24ClientError("The Agents24 deployment bootstrap could not be reached.", {
|
|
738
|
+
kind: input?.signal?.aborted ? "aborted" : "network",
|
|
739
|
+
code: input?.signal?.aborted ? "ABORTED" : "NETWORK_ERROR",
|
|
740
|
+
retryable: !input?.signal?.aborted,
|
|
741
|
+
cause
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
if (response.redirected || response.status >= 300 && response.status < 400) {
|
|
745
|
+
throw new Agents24ClientError("Client-runtime redirects are not allowed.", {
|
|
746
|
+
kind: "network",
|
|
747
|
+
code: "REDIRECT_REJECTED",
|
|
748
|
+
status: response.status
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
if (!response.ok) throw await responseError(response);
|
|
752
|
+
return objectResult(await responseJson(response), "Bootstrap");
|
|
753
|
+
},
|
|
754
|
+
chat: {
|
|
755
|
+
async stream(input, onEvent) {
|
|
756
|
+
const initial = async (onProgress) => {
|
|
757
|
+
const response = await http.request(
|
|
758
|
+
"POST",
|
|
759
|
+
deploymentPath(options.deploymentId, "/chat/stream"),
|
|
760
|
+
{
|
|
761
|
+
operation: "chat.stream",
|
|
762
|
+
accept: "text/event-stream",
|
|
763
|
+
idempotencyKey: input.idempotencyKey,
|
|
764
|
+
...input.headers ? { headers: input.headers } : {},
|
|
765
|
+
body: {
|
|
766
|
+
input: input.input,
|
|
767
|
+
attachment_ids: [...input.attachmentIds ?? []],
|
|
768
|
+
...input.threadId ? { thread_id: input.threadId } : {},
|
|
769
|
+
...input.requestedModelId ? { requested_model_id: input.requestedModelId } : {},
|
|
770
|
+
tool_inputs: input.toolInputs ?? {},
|
|
771
|
+
metadata: input.metadata ?? {},
|
|
772
|
+
client: input.client ?? { sdk_name: "@agents24/client", sdk_version: "0.1.0" }
|
|
773
|
+
},
|
|
774
|
+
...input.signal ? { signal: input.signal } : {}
|
|
775
|
+
}
|
|
776
|
+
);
|
|
777
|
+
return consumeRuntimeStream({
|
|
778
|
+
response,
|
|
779
|
+
decoder: decoder(),
|
|
780
|
+
onEvent,
|
|
781
|
+
...input.signal ? { signal: input.signal } : {},
|
|
782
|
+
onProgress
|
|
783
|
+
});
|
|
784
|
+
};
|
|
785
|
+
return reconnect(initial, input.signal, onEvent, "chat.stream", input.headers);
|
|
786
|
+
}
|
|
787
|
+
},
|
|
788
|
+
runs: {
|
|
789
|
+
async attach(input, onEvent) {
|
|
790
|
+
const initial = (onProgress) => attach(input.runId, input.cursor, input.headers, input.signal, onEvent, onProgress);
|
|
791
|
+
return reconnect(initial, input.signal, onEvent, "runs.attach", input.headers);
|
|
792
|
+
},
|
|
793
|
+
async cancel(input) {
|
|
794
|
+
const result = await http.json(
|
|
795
|
+
"POST",
|
|
796
|
+
deploymentPath(options.deploymentId, `/runs/${encodePath(input.runId)}/cancel`),
|
|
797
|
+
{
|
|
798
|
+
operation: "runs.cancel",
|
|
799
|
+
body: {},
|
|
800
|
+
idempotencyKey: input.idempotencyKey,
|
|
801
|
+
...input.signal ? { signal: input.signal } : {}
|
|
802
|
+
}
|
|
803
|
+
);
|
|
804
|
+
return objectResult(result, "Run cancellation");
|
|
805
|
+
}
|
|
806
|
+
},
|
|
807
|
+
threads: {
|
|
808
|
+
async list(input) {
|
|
809
|
+
const path = appendQuery(deploymentPath(options.deploymentId, "/threads"), {
|
|
810
|
+
skip: input?.skip,
|
|
811
|
+
limit: input?.limit
|
|
812
|
+
});
|
|
813
|
+
const result = await http.json("GET", path, {
|
|
814
|
+
operation: "threads.list",
|
|
815
|
+
...input?.signal ? { signal: input.signal } : {}
|
|
816
|
+
});
|
|
817
|
+
return objectResult(result, "Thread listing");
|
|
818
|
+
},
|
|
819
|
+
async get(input) {
|
|
820
|
+
const path = appendQuery(
|
|
821
|
+
deploymentPath(options.deploymentId, `/threads/${encodePath(input.threadId)}`),
|
|
822
|
+
{
|
|
823
|
+
limit: input.limit,
|
|
824
|
+
before_turn_index: input.beforeTurnIndex,
|
|
825
|
+
include_run_events: input.includeRunEvents
|
|
826
|
+
}
|
|
827
|
+
);
|
|
828
|
+
const result = await http.json("GET", path, {
|
|
829
|
+
operation: "threads.get",
|
|
830
|
+
...input.signal ? { signal: input.signal } : {}
|
|
831
|
+
});
|
|
832
|
+
return objectResult(result, "Thread detail");
|
|
833
|
+
},
|
|
834
|
+
async events(input, onEvent) {
|
|
835
|
+
let cursor = input.cursor;
|
|
836
|
+
let attempts = 0;
|
|
837
|
+
while (!input.signal?.aborted) {
|
|
838
|
+
try {
|
|
839
|
+
const path = appendQuery(deploymentPath(options.deploymentId, "/threads/events"), { cursor });
|
|
840
|
+
const response = await http.request("GET", path, {
|
|
841
|
+
operation: "threads.events",
|
|
842
|
+
accept: "text/event-stream",
|
|
843
|
+
...input.signal ? { signal: input.signal } : {}
|
|
844
|
+
});
|
|
845
|
+
cursor = await consumeThreadSummaryStream({
|
|
846
|
+
response,
|
|
847
|
+
decoder: decoder(),
|
|
848
|
+
onEvent,
|
|
849
|
+
...input.signal ? { signal: input.signal } : {},
|
|
850
|
+
...cursor === void 0 ? {} : { afterCursor: cursor },
|
|
851
|
+
onCursor(next) {
|
|
852
|
+
cursor = next;
|
|
853
|
+
}
|
|
854
|
+
}) ?? void 0;
|
|
855
|
+
return;
|
|
856
|
+
} catch (error) {
|
|
857
|
+
if (input.signal?.aborted || !shouldReconnect(error) || attempts >= maxReconnectAttempts) throw error;
|
|
858
|
+
attempts += 1;
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
},
|
|
862
|
+
async delete(input) {
|
|
863
|
+
const result = await http.json(
|
|
864
|
+
"DELETE",
|
|
865
|
+
deploymentPath(options.deploymentId, `/threads/${encodePath(input.threadId)}`),
|
|
866
|
+
{
|
|
867
|
+
operation: "threads.delete",
|
|
868
|
+
idempotencyKey: input.idempotencyKey,
|
|
869
|
+
...input.signal ? { signal: input.signal } : {}
|
|
870
|
+
}
|
|
871
|
+
);
|
|
872
|
+
return objectResult(result, "Thread deletion");
|
|
873
|
+
}
|
|
874
|
+
},
|
|
875
|
+
attachments: {
|
|
876
|
+
async upload(input) {
|
|
877
|
+
const multipart = options.multipart ?? createByteMultipartEncoder(resolveEncoder(options.encoder));
|
|
878
|
+
const encoded = await multipart.encode([
|
|
879
|
+
...input.threadId ? [{ field: "thread_id", value: input.threadId }] : [],
|
|
880
|
+
{ field: "files", value: input.upload }
|
|
881
|
+
]);
|
|
882
|
+
const result = await http.json(
|
|
883
|
+
"POST",
|
|
884
|
+
deploymentPath(options.deploymentId, "/attachments/upload"),
|
|
885
|
+
{
|
|
886
|
+
operation: "attachments.upload",
|
|
887
|
+
rawBody: encoded.body,
|
|
888
|
+
contentType: encoded.contentType,
|
|
889
|
+
idempotencyKey: input.idempotencyKey,
|
|
890
|
+
...input.signal ? { signal: input.signal } : {}
|
|
891
|
+
}
|
|
892
|
+
);
|
|
893
|
+
const body = objectResult(result, "Attachment upload");
|
|
894
|
+
const item = Array.isArray(body.items) ? body.items[0] : body;
|
|
895
|
+
return objectResult(item, "Attachment upload");
|
|
896
|
+
}
|
|
897
|
+
},
|
|
898
|
+
hitl: {
|
|
899
|
+
async resume(input) {
|
|
900
|
+
const result = await http.json(
|
|
901
|
+
"POST",
|
|
902
|
+
deploymentPath(
|
|
903
|
+
options.deploymentId,
|
|
904
|
+
`/runs/${encodePath(input.runId)}/hitl/${encodePath(input.interruptId)}/resume`
|
|
905
|
+
),
|
|
906
|
+
{
|
|
907
|
+
operation: "hitl.resume",
|
|
908
|
+
idempotencyKey: input.idempotencyKey,
|
|
909
|
+
body: {
|
|
910
|
+
schema_version: "agents24.hitl.resume.v2",
|
|
911
|
+
interrupt_id: input.interruptId,
|
|
912
|
+
action: input.action,
|
|
913
|
+
...input.comment ? { comment: input.comment } : {}
|
|
914
|
+
},
|
|
915
|
+
...input.signal ? { signal: input.signal } : {}
|
|
916
|
+
}
|
|
917
|
+
);
|
|
918
|
+
return objectResult(result, "HITL resume");
|
|
919
|
+
}
|
|
920
|
+
},
|
|
921
|
+
mcp: {
|
|
922
|
+
async startAuthorization(input) {
|
|
923
|
+
const result = await http.json(
|
|
924
|
+
"POST",
|
|
925
|
+
deploymentPath(
|
|
926
|
+
options.deploymentId,
|
|
927
|
+
`/runs/${encodePath(input.runId)}/mcp/servers/${encodePath(input.serverId)}/auth/start`
|
|
928
|
+
),
|
|
929
|
+
{
|
|
930
|
+
operation: "mcp.startAuthorization",
|
|
931
|
+
idempotencyKey: input.idempotencyKey,
|
|
932
|
+
body: {
|
|
933
|
+
interrupt_id: input.interruptId,
|
|
934
|
+
redirect_uri: input.redirectUri,
|
|
935
|
+
popup_nonce: input.popupNonce,
|
|
936
|
+
code_challenge: input.codeChallenge,
|
|
937
|
+
code_challenge_method: "S256"
|
|
938
|
+
},
|
|
939
|
+
...input.signal ? { signal: input.signal } : {}
|
|
940
|
+
}
|
|
941
|
+
);
|
|
942
|
+
return objectResult(result, "MCP authorization start");
|
|
943
|
+
},
|
|
944
|
+
async redeemCallback(input) {
|
|
945
|
+
const result = await http.json(
|
|
946
|
+
"POST",
|
|
947
|
+
deploymentPath(options.deploymentId, "/mcp/callback/redeem"),
|
|
948
|
+
{
|
|
949
|
+
operation: "mcp.redeemCallback",
|
|
950
|
+
idempotencyKey: input.idempotencyKey,
|
|
951
|
+
body: { code: input.code, code_verifier: input.codeVerifier },
|
|
952
|
+
...input.signal ? { signal: input.signal } : {}
|
|
953
|
+
}
|
|
954
|
+
);
|
|
955
|
+
return objectResult(result, "MCP callback redemption");
|
|
956
|
+
}
|
|
957
|
+
},
|
|
958
|
+
sessions: {
|
|
959
|
+
async revoke(input) {
|
|
960
|
+
if (!options.sessionProvider.revoke) {
|
|
961
|
+
throw new Agents24ClientError("The configured session provider cannot revoke sessions.", {
|
|
962
|
+
kind: "missing_capability",
|
|
963
|
+
code: "SESSION_REVOKE_UNAVAILABLE"
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
await options.sessionProvider.revoke({
|
|
967
|
+
idempotencyKey: input?.idempotencyKey ?? ids.createId(),
|
|
968
|
+
...input?.signal ? { signal: input.signal } : {}
|
|
969
|
+
});
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
};
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
export { Agents24ClientError, AuthenticatedHttp, absoluteUrl, canonicalHtu, createAgents24Client, createByteMultipartEncoder, defaultClock, defaultIds, dpopTokenRequest, encodePath, missingCapability, normalizeBaseUrl, resolveEncoder, resolveFetch, responseError, responseJson };
|
|
976
|
+
//# sourceMappingURL=chunk-45ITVMX3.js.map
|
|
977
|
+
//# sourceMappingURL=chunk-45ITVMX3.js.map
|