@cadraos/sdk 0.1.2
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 +401 -0
- package/dist/chat/index.cjs +2330 -0
- package/dist/chat/index.cjs.map +1 -0
- package/dist/chat/index.d.cts +974 -0
- package/dist/chat/index.d.ts +974 -0
- package/dist/chat/index.js +2277 -0
- package/dist/chat/index.js.map +1 -0
- package/dist/index.cjs +1913 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1904 -0
- package/dist/index.d.ts +1904 -0
- package/dist/index.js +1901 -0
- package/dist/index.js.map +1 -0
- package/package.json +97 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1901 @@
|
|
|
1
|
+
// src/resources/base.ts
|
|
2
|
+
var BaseResourceAPI = class {
|
|
3
|
+
http;
|
|
4
|
+
basePath;
|
|
5
|
+
constructor(http, basePath) {
|
|
6
|
+
this.http = http;
|
|
7
|
+
this.basePath = basePath;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Build query parameters from list options
|
|
11
|
+
*/
|
|
12
|
+
buildListQuery(options) {
|
|
13
|
+
if (!options) return {};
|
|
14
|
+
return {
|
|
15
|
+
limit: options.limit,
|
|
16
|
+
offset: options.offset,
|
|
17
|
+
sort: options.sort,
|
|
18
|
+
order: options.order
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* HTTP GET request helper
|
|
23
|
+
*/
|
|
24
|
+
async httpGet(path, query) {
|
|
25
|
+
return this.http.get(`${this.basePath}${path}`, query);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* HTTP POST request helper
|
|
29
|
+
*/
|
|
30
|
+
async httpPost(path, body, options) {
|
|
31
|
+
return this.http.post(`${this.basePath}${path}`, body, options);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* HTTP PATCH request helper
|
|
35
|
+
*/
|
|
36
|
+
async httpPatch(path, body, options) {
|
|
37
|
+
return this.http.patch(`${this.basePath}${path}`, body, options);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* HTTP DELETE request helper
|
|
41
|
+
*/
|
|
42
|
+
async httpDelete(path) {
|
|
43
|
+
return this.http.delete(`${this.basePath}${path}`);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* List resources with pagination
|
|
47
|
+
*/
|
|
48
|
+
async listResources(path, options) {
|
|
49
|
+
const query = this.buildListQuery(options);
|
|
50
|
+
return this.httpGet(path, query);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// src/errors/sdk-errors.ts
|
|
55
|
+
var AISaaSError = class extends Error {
|
|
56
|
+
/** Error code */
|
|
57
|
+
code;
|
|
58
|
+
/** HTTP status code */
|
|
59
|
+
status;
|
|
60
|
+
/** Additional error details */
|
|
61
|
+
details;
|
|
62
|
+
/** Request ID from server (for debugging) */
|
|
63
|
+
requestId;
|
|
64
|
+
constructor(message, code, status, details, requestId) {
|
|
65
|
+
super(message);
|
|
66
|
+
this.name = "AISaaSError";
|
|
67
|
+
this.code = code;
|
|
68
|
+
this.status = status;
|
|
69
|
+
this.details = details;
|
|
70
|
+
this.requestId = requestId;
|
|
71
|
+
if (Error.captureStackTrace) {
|
|
72
|
+
Error.captureStackTrace(this, this.constructor);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
var AuthenticationError = class extends AISaaSError {
|
|
77
|
+
constructor(message = "Authentication failed", code = "authentication_error", details, requestId) {
|
|
78
|
+
super(message, code, 401, details, requestId);
|
|
79
|
+
this.name = "AuthenticationError";
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
var AuthorizationError = class extends AISaaSError {
|
|
83
|
+
constructor(message = "Access denied", code = "authorization_error", details, requestId) {
|
|
84
|
+
super(message, code, 403, details, requestId);
|
|
85
|
+
this.name = "AuthorizationError";
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
var NotFoundError = class extends AISaaSError {
|
|
89
|
+
constructor(message = "Resource not found", code = "not_found", details, requestId) {
|
|
90
|
+
super(message, code, 404, details, requestId);
|
|
91
|
+
this.name = "NotFoundError";
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
var ValidationError = class extends AISaaSError {
|
|
95
|
+
/** Field-level validation errors */
|
|
96
|
+
errors;
|
|
97
|
+
constructor(message = "Validation failed", errors = [], details, requestId) {
|
|
98
|
+
super(message, "validation_error", 400, details, requestId);
|
|
99
|
+
this.name = "ValidationError";
|
|
100
|
+
this.errors = errors;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
var RateLimitError = class extends AISaaSError {
|
|
104
|
+
/** Seconds until rate limit resets */
|
|
105
|
+
retryAfter;
|
|
106
|
+
constructor(message = "Rate limit exceeded", retryAfter, details, requestId) {
|
|
107
|
+
super(message, "rate_limit_error", 429, details, requestId);
|
|
108
|
+
this.name = "RateLimitError";
|
|
109
|
+
this.retryAfter = retryAfter;
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
var ServerError = class extends AISaaSError {
|
|
113
|
+
constructor(message = "Server error", status = 500, details, requestId) {
|
|
114
|
+
super(message, "server_error", status, details, requestId);
|
|
115
|
+
this.name = "ServerError";
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
var ConflictError = class extends AISaaSError {
|
|
119
|
+
constructor(message = "Resource conflict", details, requestId) {
|
|
120
|
+
super(message, "conflict", 409, details, requestId);
|
|
121
|
+
this.name = "ConflictError";
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
var TimeoutError = class extends AISaaSError {
|
|
125
|
+
constructor(message = "Request timed out", details, requestId) {
|
|
126
|
+
super(message, "timeout", 408, details, requestId);
|
|
127
|
+
this.name = "TimeoutError";
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
var NetworkError = class extends AISaaSError {
|
|
131
|
+
constructor(message = "Network error", details) {
|
|
132
|
+
super(message, "network_error", 0, details);
|
|
133
|
+
this.name = "NetworkError";
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
function parseApiError(status, body, requestId) {
|
|
137
|
+
const errorBody = body;
|
|
138
|
+
const message = errorBody?.error?.message ?? "An error occurred";
|
|
139
|
+
const code = errorBody?.error?.code ?? "unknown_error";
|
|
140
|
+
const details = errorBody?.error?.details;
|
|
141
|
+
switch (status) {
|
|
142
|
+
case 400:
|
|
143
|
+
case 422: {
|
|
144
|
+
const fieldErrors = details?.errors;
|
|
145
|
+
if (fieldErrors) {
|
|
146
|
+
const errors = [];
|
|
147
|
+
for (const [field, messages] of Object.entries(fieldErrors)) {
|
|
148
|
+
for (const msg of messages) {
|
|
149
|
+
errors.push({ field, message: msg });
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return new ValidationError(message, errors, details, requestId);
|
|
153
|
+
}
|
|
154
|
+
return new ValidationError(message, [], details, requestId);
|
|
155
|
+
}
|
|
156
|
+
case 401:
|
|
157
|
+
return new AuthenticationError(message, code, details, requestId);
|
|
158
|
+
case 403:
|
|
159
|
+
return new AuthorizationError(message, code, details, requestId);
|
|
160
|
+
case 404:
|
|
161
|
+
return new NotFoundError(message, code, details, requestId);
|
|
162
|
+
case 409:
|
|
163
|
+
return new ConflictError(message, details, requestId);
|
|
164
|
+
case 429: {
|
|
165
|
+
const retryAfter = details?.retryAfter;
|
|
166
|
+
return new RateLimitError(message, retryAfter, details, requestId);
|
|
167
|
+
}
|
|
168
|
+
default:
|
|
169
|
+
if (status >= 500) {
|
|
170
|
+
return new ServerError(message, status, details, requestId);
|
|
171
|
+
}
|
|
172
|
+
return new AISaaSError(message, code, status, details, requestId);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// src/utils/retry.ts
|
|
177
|
+
var DEFAULT_RETRY_CONFIG = {
|
|
178
|
+
maxRetries: 3,
|
|
179
|
+
baseDelayMs: 1e3,
|
|
180
|
+
maxDelayMs: 3e4,
|
|
181
|
+
jitterFactor: 0.1
|
|
182
|
+
};
|
|
183
|
+
function shouldRetry(error, attempt, maxRetries) {
|
|
184
|
+
if (attempt >= maxRetries) {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
if (error instanceof RateLimitError) {
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
if (error instanceof ServerError) {
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
if (error instanceof Error && error.name === "NetworkError") {
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
if (error instanceof Error && error.name === "TimeoutError") {
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
function calculateRetryDelay(attempt, config, retryAfter) {
|
|
202
|
+
if (retryAfter !== void 0 && retryAfter > 0) {
|
|
203
|
+
return retryAfter * 1e3;
|
|
204
|
+
}
|
|
205
|
+
const exponentialDelay = config.baseDelayMs * Math.pow(2, attempt);
|
|
206
|
+
const cappedDelay = Math.min(exponentialDelay, config.maxDelayMs);
|
|
207
|
+
const jitter = cappedDelay * config.jitterFactor * Math.random();
|
|
208
|
+
return cappedDelay + jitter;
|
|
209
|
+
}
|
|
210
|
+
function sleep(ms) {
|
|
211
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
212
|
+
}
|
|
213
|
+
async function withRetry(operation, config = {}) {
|
|
214
|
+
const fullConfig = { ...DEFAULT_RETRY_CONFIG, ...config };
|
|
215
|
+
let lastError;
|
|
216
|
+
for (let attempt = 0; attempt <= fullConfig.maxRetries; attempt++) {
|
|
217
|
+
try {
|
|
218
|
+
return await operation();
|
|
219
|
+
} catch (error) {
|
|
220
|
+
lastError = error;
|
|
221
|
+
if (!shouldRetry(error, attempt, fullConfig.maxRetries)) {
|
|
222
|
+
throw error;
|
|
223
|
+
}
|
|
224
|
+
const retryAfter = error instanceof RateLimitError ? error.retryAfter : void 0;
|
|
225
|
+
const delay = calculateRetryDelay(attempt, fullConfig, retryAfter);
|
|
226
|
+
await sleep(delay);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
throw lastError;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// src/utils/http.ts
|
|
233
|
+
var HttpClient = class {
|
|
234
|
+
config;
|
|
235
|
+
tokenRefreshAttempts = 0;
|
|
236
|
+
maxTokenRefreshAttempts = 2;
|
|
237
|
+
constructor(config) {
|
|
238
|
+
this.config = config;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Get authorization header value
|
|
242
|
+
*/
|
|
243
|
+
async getAuthHeader() {
|
|
244
|
+
if (this.config.apiKey) {
|
|
245
|
+
return `Bearer ${this.config.apiKey}`;
|
|
246
|
+
}
|
|
247
|
+
if (this.config.tokenProvider) {
|
|
248
|
+
const token = await this.config.tokenProvider();
|
|
249
|
+
return `Bearer ${token}`;
|
|
250
|
+
}
|
|
251
|
+
if (this.config.token) {
|
|
252
|
+
return `Bearer ${this.config.token}`;
|
|
253
|
+
}
|
|
254
|
+
throw new Error("No authentication configured. Provide apiKey, token, or tokenProvider.");
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Build full URL with query parameters
|
|
258
|
+
*/
|
|
259
|
+
buildUrl(path, query) {
|
|
260
|
+
const url = new URL(path, this.config.baseUrl);
|
|
261
|
+
if (query) {
|
|
262
|
+
for (const [key, value] of Object.entries(query)) {
|
|
263
|
+
if (value !== void 0) {
|
|
264
|
+
url.searchParams.set(key, String(value));
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return url.toString();
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Make an HTTP request
|
|
272
|
+
*/
|
|
273
|
+
async request(options) {
|
|
274
|
+
const makeRequest = async () => {
|
|
275
|
+
const url = this.buildUrl(options.path, options.query);
|
|
276
|
+
const authHeader = await this.getAuthHeader();
|
|
277
|
+
const headers = {
|
|
278
|
+
"Authorization": authHeader,
|
|
279
|
+
"X-Org-Id": String(this.config.orgId),
|
|
280
|
+
"Content-Type": "application/json",
|
|
281
|
+
...this.config.headers,
|
|
282
|
+
...options.headers
|
|
283
|
+
};
|
|
284
|
+
if (options.idempotencyKey) {
|
|
285
|
+
headers["Idempotency-Key"] = options.idempotencyKey;
|
|
286
|
+
}
|
|
287
|
+
const controller = new AbortController();
|
|
288
|
+
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
289
|
+
try {
|
|
290
|
+
const response = await fetch(url, {
|
|
291
|
+
method: options.method,
|
|
292
|
+
headers,
|
|
293
|
+
body: options.body !== void 0 ? JSON.stringify(options.body) : void 0,
|
|
294
|
+
signal: controller.signal
|
|
295
|
+
});
|
|
296
|
+
clearTimeout(timeoutId);
|
|
297
|
+
const requestId = response.headers.get("X-Request-Id") ?? void 0;
|
|
298
|
+
let body;
|
|
299
|
+
const contentType = response.headers.get("Content-Type");
|
|
300
|
+
if (contentType?.includes("application/json")) {
|
|
301
|
+
body = await response.json();
|
|
302
|
+
} else {
|
|
303
|
+
body = await response.text();
|
|
304
|
+
}
|
|
305
|
+
if (!response.ok) {
|
|
306
|
+
if (response.status === 401 && this.config.tokenProvider) {
|
|
307
|
+
this.tokenRefreshAttempts++;
|
|
308
|
+
if (this.tokenRefreshAttempts < this.maxTokenRefreshAttempts) {
|
|
309
|
+
return this.request(options);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
throw parseApiError(response.status, body, requestId);
|
|
313
|
+
}
|
|
314
|
+
this.tokenRefreshAttempts = 0;
|
|
315
|
+
const apiResponse = body;
|
|
316
|
+
if ("success" in apiResponse && apiResponse.success) {
|
|
317
|
+
return apiResponse.data;
|
|
318
|
+
}
|
|
319
|
+
return body;
|
|
320
|
+
} catch (error) {
|
|
321
|
+
clearTimeout(timeoutId);
|
|
322
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
323
|
+
throw new TimeoutError(`Request timed out after ${this.config.timeout}ms`);
|
|
324
|
+
}
|
|
325
|
+
if (error instanceof TypeError && error.message.includes("fetch")) {
|
|
326
|
+
throw new NetworkError(`Network error: ${error.message}`);
|
|
327
|
+
}
|
|
328
|
+
throw error;
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
if (options.skipRetry) {
|
|
332
|
+
return makeRequest();
|
|
333
|
+
}
|
|
334
|
+
return withRetry(makeRequest, this.config.retry);
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* GET request
|
|
338
|
+
*/
|
|
339
|
+
async get(path, query) {
|
|
340
|
+
return this.request({
|
|
341
|
+
method: "GET",
|
|
342
|
+
path,
|
|
343
|
+
query
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* POST request
|
|
348
|
+
*/
|
|
349
|
+
async post(path, body, options) {
|
|
350
|
+
return this.request({
|
|
351
|
+
method: "POST",
|
|
352
|
+
path,
|
|
353
|
+
body,
|
|
354
|
+
idempotencyKey: options?.idempotencyKey,
|
|
355
|
+
skipRetry: options?.skipRetry
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* PATCH request
|
|
360
|
+
*/
|
|
361
|
+
async patch(path, body, options) {
|
|
362
|
+
return this.request({
|
|
363
|
+
method: "PATCH",
|
|
364
|
+
path,
|
|
365
|
+
body,
|
|
366
|
+
idempotencyKey: options?.idempotencyKey
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* DELETE request
|
|
371
|
+
*/
|
|
372
|
+
async delete(path) {
|
|
373
|
+
return this.request({
|
|
374
|
+
method: "DELETE",
|
|
375
|
+
path,
|
|
376
|
+
skipRetry: true
|
|
377
|
+
// Don't retry deletes
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Update configuration
|
|
382
|
+
*/
|
|
383
|
+
updateConfig(config) {
|
|
384
|
+
this.config = { ...this.config, ...config };
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
function generateIdempotencyKey() {
|
|
388
|
+
const timestamp = Date.now().toString(36);
|
|
389
|
+
const random = Math.random().toString(36).substring(2, 15);
|
|
390
|
+
return `idem_${timestamp}_${random}`;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// src/streaming/sse-client.ts
|
|
394
|
+
var SSEClient = class {
|
|
395
|
+
config;
|
|
396
|
+
abortController = null;
|
|
397
|
+
connected = false;
|
|
398
|
+
constructor(config) {
|
|
399
|
+
this.config = config;
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Connect to SSE endpoint
|
|
403
|
+
*/
|
|
404
|
+
async connect() {
|
|
405
|
+
this.abortController = new AbortController();
|
|
406
|
+
try {
|
|
407
|
+
const response = await fetch(this.config.url, {
|
|
408
|
+
method: "GET",
|
|
409
|
+
headers: {
|
|
410
|
+
"Authorization": this.config.authHeader,
|
|
411
|
+
"X-Org-Id": String(this.config.orgId),
|
|
412
|
+
"Accept": "text/event-stream",
|
|
413
|
+
"Cache-Control": "no-cache"
|
|
414
|
+
},
|
|
415
|
+
signal: this.abortController.signal
|
|
416
|
+
});
|
|
417
|
+
if (!response.ok) {
|
|
418
|
+
throw new Error(`SSE connection failed: ${response.status} ${response.statusText}`);
|
|
419
|
+
}
|
|
420
|
+
if (!response.body) {
|
|
421
|
+
throw new Error("Response body not available");
|
|
422
|
+
}
|
|
423
|
+
this.connected = true;
|
|
424
|
+
this.config.onConnectionChange(true);
|
|
425
|
+
await this.parseStream(response.body);
|
|
426
|
+
} catch (error) {
|
|
427
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
this.config.onError(error instanceof Error ? error : new Error(String(error)));
|
|
431
|
+
} finally {
|
|
432
|
+
this.connected = false;
|
|
433
|
+
this.config.onConnectionChange(false);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Disconnect from SSE endpoint
|
|
438
|
+
*/
|
|
439
|
+
disconnect() {
|
|
440
|
+
if (this.abortController) {
|
|
441
|
+
this.abortController.abort();
|
|
442
|
+
this.abortController = null;
|
|
443
|
+
}
|
|
444
|
+
this.connected = false;
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Check if connected
|
|
448
|
+
*/
|
|
449
|
+
isConnected() {
|
|
450
|
+
return this.connected;
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Parse SSE stream
|
|
454
|
+
*/
|
|
455
|
+
async parseStream(body) {
|
|
456
|
+
const reader = body.getReader();
|
|
457
|
+
const decoder = new TextDecoder();
|
|
458
|
+
let buffer = "";
|
|
459
|
+
let currentEvent = {};
|
|
460
|
+
try {
|
|
461
|
+
while (true) {
|
|
462
|
+
const { done, value } = await reader.read();
|
|
463
|
+
if (done) {
|
|
464
|
+
break;
|
|
465
|
+
}
|
|
466
|
+
buffer += decoder.decode(value, { stream: true });
|
|
467
|
+
const lines = buffer.split("\n");
|
|
468
|
+
buffer = lines.pop() ?? "";
|
|
469
|
+
for (const line of lines) {
|
|
470
|
+
if (line === "") {
|
|
471
|
+
if (currentEvent.type && currentEvent.data !== void 0) {
|
|
472
|
+
this.dispatchEvent(currentEvent);
|
|
473
|
+
}
|
|
474
|
+
currentEvent = {};
|
|
475
|
+
continue;
|
|
476
|
+
}
|
|
477
|
+
if (line.startsWith(":")) {
|
|
478
|
+
continue;
|
|
479
|
+
}
|
|
480
|
+
const colonIndex = line.indexOf(":");
|
|
481
|
+
if (colonIndex === -1) {
|
|
482
|
+
continue;
|
|
483
|
+
}
|
|
484
|
+
const field = line.substring(0, colonIndex);
|
|
485
|
+
let value2 = line.substring(colonIndex + 1);
|
|
486
|
+
if (value2.startsWith(" ")) {
|
|
487
|
+
value2 = value2.substring(1);
|
|
488
|
+
}
|
|
489
|
+
switch (field) {
|
|
490
|
+
case "event":
|
|
491
|
+
currentEvent.type = value2;
|
|
492
|
+
break;
|
|
493
|
+
case "id":
|
|
494
|
+
currentEvent.id = value2;
|
|
495
|
+
break;
|
|
496
|
+
case "data":
|
|
497
|
+
currentEvent.data = currentEvent.data ? currentEvent.data + "\n" + value2 : value2;
|
|
498
|
+
break;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
} finally {
|
|
503
|
+
reader.releaseLock();
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Dispatch parsed event
|
|
508
|
+
*/
|
|
509
|
+
dispatchEvent(event) {
|
|
510
|
+
try {
|
|
511
|
+
let data;
|
|
512
|
+
try {
|
|
513
|
+
data = JSON.parse(event.data);
|
|
514
|
+
} catch {
|
|
515
|
+
data = event.data;
|
|
516
|
+
}
|
|
517
|
+
const sseEvent = {
|
|
518
|
+
type: event.type,
|
|
519
|
+
id: event.id,
|
|
520
|
+
data
|
|
521
|
+
};
|
|
522
|
+
this.config.onEvent(sseEvent);
|
|
523
|
+
} catch (error) {
|
|
524
|
+
this.config.onError(
|
|
525
|
+
error instanceof Error ? error : new Error(`Failed to parse event: ${String(error)}`)
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
};
|
|
530
|
+
|
|
531
|
+
// src/streaming/stream-controller.ts
|
|
532
|
+
var DEFAULT_STREAMING_CONFIG = {
|
|
533
|
+
maxReconnectAttempts: 5,
|
|
534
|
+
reconnectBaseDelayMs: 1e3,
|
|
535
|
+
reconnectMaxDelayMs: 1e4,
|
|
536
|
+
activityTimeoutMs: 3e4,
|
|
537
|
+
pollingIntervalMs: 2e3
|
|
538
|
+
};
|
|
539
|
+
var ExecutionStreamControllerImpl = class {
|
|
540
|
+
options;
|
|
541
|
+
config;
|
|
542
|
+
sseClient = null;
|
|
543
|
+
status = "connecting";
|
|
544
|
+
reconnectAttempts = 0;
|
|
545
|
+
seenEventIds = /* @__PURE__ */ new Set();
|
|
546
|
+
_lastEventId = null;
|
|
547
|
+
activityTimeoutId = null;
|
|
548
|
+
pollingIntervalId = null;
|
|
549
|
+
finalExecution = null;
|
|
550
|
+
finalError = null;
|
|
551
|
+
// Event callbacks
|
|
552
|
+
listeners = {
|
|
553
|
+
log: [],
|
|
554
|
+
toolCall: [],
|
|
555
|
+
toolResult: [],
|
|
556
|
+
plan: [],
|
|
557
|
+
complete: [],
|
|
558
|
+
error: [],
|
|
559
|
+
connectionChange: []
|
|
560
|
+
};
|
|
561
|
+
// Promise for wait()
|
|
562
|
+
waitPromise = null;
|
|
563
|
+
waitResolve = null;
|
|
564
|
+
waitReject = null;
|
|
565
|
+
constructor(options) {
|
|
566
|
+
this.options = options;
|
|
567
|
+
this.config = { ...DEFAULT_STREAMING_CONFIG, ...options.config };
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* Get the last event ID (for resume support)
|
|
571
|
+
*/
|
|
572
|
+
get lastEventId() {
|
|
573
|
+
return this._lastEventId;
|
|
574
|
+
}
|
|
575
|
+
/**
|
|
576
|
+
* Connect to the execution stream
|
|
577
|
+
*/
|
|
578
|
+
async connect() {
|
|
579
|
+
this.status = "connecting";
|
|
580
|
+
this.reconnectAttempts = 0;
|
|
581
|
+
try {
|
|
582
|
+
await this.connectSSE();
|
|
583
|
+
} catch (error) {
|
|
584
|
+
await this.handleConnectionError(error);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* Register event listener
|
|
589
|
+
*/
|
|
590
|
+
on(event, callback) {
|
|
591
|
+
const listeners = this.listeners[event];
|
|
592
|
+
if (listeners) {
|
|
593
|
+
listeners.push(callback);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
/**
|
|
597
|
+
* Cancel the stream
|
|
598
|
+
*/
|
|
599
|
+
cancel() {
|
|
600
|
+
this.status = "closed";
|
|
601
|
+
this.stopActivityTimeout();
|
|
602
|
+
this.stopPolling();
|
|
603
|
+
if (this.sseClient) {
|
|
604
|
+
this.sseClient.disconnect();
|
|
605
|
+
this.sseClient = null;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* Wait for completion
|
|
610
|
+
*/
|
|
611
|
+
wait() {
|
|
612
|
+
if (this.finalExecution) {
|
|
613
|
+
return Promise.resolve(this.finalExecution);
|
|
614
|
+
}
|
|
615
|
+
if (this.finalError) {
|
|
616
|
+
return Promise.reject(new AISaaSError(
|
|
617
|
+
this.finalError.error,
|
|
618
|
+
this.finalError.errorCode ?? "execution_error",
|
|
619
|
+
500
|
|
620
|
+
));
|
|
621
|
+
}
|
|
622
|
+
if (!this.waitPromise) {
|
|
623
|
+
this.waitPromise = new Promise((resolve, reject) => {
|
|
624
|
+
this.waitResolve = resolve;
|
|
625
|
+
this.waitReject = reject;
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
return this.waitPromise;
|
|
629
|
+
}
|
|
630
|
+
// ===== Private methods =====
|
|
631
|
+
/**
|
|
632
|
+
* Connect to SSE endpoint
|
|
633
|
+
*/
|
|
634
|
+
async connectSSE() {
|
|
635
|
+
const url = `${this.options.baseUrl}/agents/runs/${this.options.executionId}/stream`;
|
|
636
|
+
this.sseClient = new SSEClient({
|
|
637
|
+
url,
|
|
638
|
+
authHeader: `Bearer ${this.options.apiKey}`,
|
|
639
|
+
orgId: this.options.orgId,
|
|
640
|
+
onEvent: (event) => this.handleEvent(event),
|
|
641
|
+
onError: (error) => this.handleConnectionError(error),
|
|
642
|
+
onConnectionChange: (connected) => {
|
|
643
|
+
if (connected) {
|
|
644
|
+
this.status = "connected";
|
|
645
|
+
this.reconnectAttempts = 0;
|
|
646
|
+
this.resetActivityTimeout();
|
|
647
|
+
}
|
|
648
|
+
this.emit("connectionChange", { connected, usingFallback: false });
|
|
649
|
+
}
|
|
650
|
+
});
|
|
651
|
+
await this.sseClient.connect();
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Handle incoming SSE event
|
|
655
|
+
*/
|
|
656
|
+
handleEvent(event) {
|
|
657
|
+
this.resetActivityTimeout();
|
|
658
|
+
if (event.id) {
|
|
659
|
+
if (this.seenEventIds.has(event.id)) {
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
this.seenEventIds.add(event.id);
|
|
663
|
+
this._lastEventId = event.id;
|
|
664
|
+
if (this.seenEventIds.size > 1e3) {
|
|
665
|
+
const ids = Array.from(this.seenEventIds);
|
|
666
|
+
this.seenEventIds = new Set(ids.slice(-500));
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
const data = event.data;
|
|
670
|
+
switch (event.type) {
|
|
671
|
+
case "log":
|
|
672
|
+
this.emit("log", data.log);
|
|
673
|
+
break;
|
|
674
|
+
case "tool_call":
|
|
675
|
+
this.emit("toolCall", {
|
|
676
|
+
toolCallId: data.toolCallId,
|
|
677
|
+
toolName: data.toolName,
|
|
678
|
+
inputs: data.args,
|
|
679
|
+
stepIndex: data.stepIndex ?? 0
|
|
680
|
+
});
|
|
681
|
+
break;
|
|
682
|
+
case "tool_result":
|
|
683
|
+
this.emit("toolResult", {
|
|
684
|
+
toolCallId: data.toolCallId,
|
|
685
|
+
toolName: data.toolName,
|
|
686
|
+
result: data.result,
|
|
687
|
+
durationMs: data.durationMs
|
|
688
|
+
});
|
|
689
|
+
break;
|
|
690
|
+
case "complete":
|
|
691
|
+
this.handleComplete(data);
|
|
692
|
+
break;
|
|
693
|
+
case "error":
|
|
694
|
+
this.handleError({
|
|
695
|
+
error: data.error,
|
|
696
|
+
errorCode: data.errorCode
|
|
697
|
+
});
|
|
698
|
+
break;
|
|
699
|
+
case "timeout":
|
|
700
|
+
if (data.retryable) {
|
|
701
|
+
this.handleConnectionError(new Error("Stream timeout"));
|
|
702
|
+
} else {
|
|
703
|
+
this.handleError({
|
|
704
|
+
error: data.error,
|
|
705
|
+
errorCode: "timeout"
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
break;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* Handle completion
|
|
713
|
+
*/
|
|
714
|
+
handleComplete(data) {
|
|
715
|
+
this.status = "closed";
|
|
716
|
+
this.stopActivityTimeout();
|
|
717
|
+
const execution = {
|
|
718
|
+
uuid: this.options.executionId,
|
|
719
|
+
agentUuid: "",
|
|
720
|
+
status: "completed",
|
|
721
|
+
input: { task: "" },
|
|
722
|
+
output: data.output,
|
|
723
|
+
logs: [],
|
|
724
|
+
tokenUsage: data.tokenUsage,
|
|
725
|
+
cost: data.cost,
|
|
726
|
+
queuedAt: "",
|
|
727
|
+
...data
|
|
728
|
+
};
|
|
729
|
+
this.finalExecution = execution;
|
|
730
|
+
this.emit("complete", { execution });
|
|
731
|
+
if (this.waitResolve) {
|
|
732
|
+
this.waitResolve(execution);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* Handle error
|
|
737
|
+
*/
|
|
738
|
+
handleError(error) {
|
|
739
|
+
this.status = "closed";
|
|
740
|
+
this.stopActivityTimeout();
|
|
741
|
+
this.finalError = error;
|
|
742
|
+
this.emit("error", error);
|
|
743
|
+
if (this.waitReject) {
|
|
744
|
+
this.waitReject(new AISaaSError(
|
|
745
|
+
error.error,
|
|
746
|
+
error.errorCode ?? "execution_error",
|
|
747
|
+
500
|
|
748
|
+
));
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* Handle connection error
|
|
753
|
+
*/
|
|
754
|
+
async handleConnectionError(error) {
|
|
755
|
+
if (this.status === "closed") {
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
if (this.reconnectAttempts < this.config.maxReconnectAttempts) {
|
|
759
|
+
this.status = "reconnecting";
|
|
760
|
+
this.reconnectAttempts++;
|
|
761
|
+
const delay = Math.min(
|
|
762
|
+
this.config.reconnectBaseDelayMs * Math.pow(2, this.reconnectAttempts),
|
|
763
|
+
this.config.reconnectMaxDelayMs
|
|
764
|
+
);
|
|
765
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
766
|
+
if (this.status === "closed") {
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
try {
|
|
770
|
+
await this.connectSSE();
|
|
771
|
+
} catch {
|
|
772
|
+
await this.handleConnectionError(error);
|
|
773
|
+
}
|
|
774
|
+
} else {
|
|
775
|
+
this.status = "fallback_polling";
|
|
776
|
+
this.emit("connectionChange", { connected: false, usingFallback: true });
|
|
777
|
+
this.startPolling();
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* Start polling fallback
|
|
782
|
+
*/
|
|
783
|
+
startPolling() {
|
|
784
|
+
this.pollingIntervalId = setInterval(async () => {
|
|
785
|
+
try {
|
|
786
|
+
const execution = await this.options.getExecution(this.options.executionId);
|
|
787
|
+
for (const log of execution.logs) {
|
|
788
|
+
if (!this.seenEventIds.has(log.uuid)) {
|
|
789
|
+
this.seenEventIds.add(log.uuid);
|
|
790
|
+
this.emit("log", log);
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
if (execution.status === "completed") {
|
|
794
|
+
this.stopPolling();
|
|
795
|
+
this.handleComplete(execution);
|
|
796
|
+
} else if (execution.status === "failed" || execution.status === "cancelled") {
|
|
797
|
+
this.stopPolling();
|
|
798
|
+
this.handleError({
|
|
799
|
+
error: execution.error ?? `Execution ${execution.status}`,
|
|
800
|
+
errorCode: execution.status
|
|
801
|
+
});
|
|
802
|
+
}
|
|
803
|
+
} catch (error) {
|
|
804
|
+
console.error("Polling error:", error);
|
|
805
|
+
}
|
|
806
|
+
}, this.config.pollingIntervalMs);
|
|
807
|
+
}
|
|
808
|
+
/**
|
|
809
|
+
* Stop polling
|
|
810
|
+
*/
|
|
811
|
+
stopPolling() {
|
|
812
|
+
if (this.pollingIntervalId) {
|
|
813
|
+
clearInterval(this.pollingIntervalId);
|
|
814
|
+
this.pollingIntervalId = null;
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* Reset activity timeout
|
|
819
|
+
*/
|
|
820
|
+
resetActivityTimeout() {
|
|
821
|
+
this.stopActivityTimeout();
|
|
822
|
+
this.activityTimeoutId = setTimeout(() => {
|
|
823
|
+
if (this.sseClient) {
|
|
824
|
+
this.sseClient.disconnect();
|
|
825
|
+
}
|
|
826
|
+
this.handleConnectionError(new Error("Activity timeout"));
|
|
827
|
+
}, this.config.activityTimeoutMs);
|
|
828
|
+
}
|
|
829
|
+
/**
|
|
830
|
+
* Stop activity timeout
|
|
831
|
+
*/
|
|
832
|
+
stopActivityTimeout() {
|
|
833
|
+
if (this.activityTimeoutId) {
|
|
834
|
+
clearTimeout(this.activityTimeoutId);
|
|
835
|
+
this.activityTimeoutId = null;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
/**
|
|
839
|
+
* Emit event to listeners
|
|
840
|
+
*/
|
|
841
|
+
emit(event, data) {
|
|
842
|
+
const listeners = this.listeners[event];
|
|
843
|
+
if (listeners) {
|
|
844
|
+
for (const listener of listeners) {
|
|
845
|
+
try {
|
|
846
|
+
listener(data);
|
|
847
|
+
} catch (error) {
|
|
848
|
+
console.error(`Error in ${event} listener:`, error);
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
};
|
|
854
|
+
function createExecutionStreamController(options) {
|
|
855
|
+
return new ExecutionStreamControllerImpl(options);
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// src/resources/agents.ts
|
|
859
|
+
var AgentsAPI = class extends BaseResourceAPI {
|
|
860
|
+
constructor(http, getStreamConfig) {
|
|
861
|
+
super(http, "/agents");
|
|
862
|
+
this.getStreamConfig = getStreamConfig;
|
|
863
|
+
}
|
|
864
|
+
// ===== LIST Operations =====
|
|
865
|
+
/**
|
|
866
|
+
* List all agents in the organization
|
|
867
|
+
*
|
|
868
|
+
* @param options - List options (pagination, filtering)
|
|
869
|
+
* @returns Paginated list of agents
|
|
870
|
+
*
|
|
871
|
+
* @example
|
|
872
|
+
* ```typescript
|
|
873
|
+
* const { data: agents, pagination } = await client.agents.list({ limit: 10 });
|
|
874
|
+
* ```
|
|
875
|
+
*/
|
|
876
|
+
async list(options) {
|
|
877
|
+
const query = {
|
|
878
|
+
...this.buildListQuery(options),
|
|
879
|
+
status: options?.status,
|
|
880
|
+
type: options?.type
|
|
881
|
+
};
|
|
882
|
+
return this.httpGet("", query);
|
|
883
|
+
}
|
|
884
|
+
/**
|
|
885
|
+
* Get a single agent by UUID
|
|
886
|
+
*
|
|
887
|
+
* @param uuid - Agent UUID
|
|
888
|
+
* @returns Agent with configuration
|
|
889
|
+
*
|
|
890
|
+
* @example
|
|
891
|
+
* ```typescript
|
|
892
|
+
* const agent = await client.agents.get('agent-uuid');
|
|
893
|
+
* console.log(agent.config);
|
|
894
|
+
* ```
|
|
895
|
+
*/
|
|
896
|
+
async get(uuid) {
|
|
897
|
+
return this.httpGet(`/${uuid}`);
|
|
898
|
+
}
|
|
899
|
+
// ===== EXECUTE Operations =====
|
|
900
|
+
/**
|
|
901
|
+
* Start an agent execution (async)
|
|
902
|
+
*
|
|
903
|
+
* Returns immediately with execution ID. Use getExecution() to poll
|
|
904
|
+
* for results, or use stream() for real-time updates.
|
|
905
|
+
*
|
|
906
|
+
* @param uuid - Agent UUID
|
|
907
|
+
* @param input - Execution input (task, context, options)
|
|
908
|
+
* @returns Execution ID and initial status
|
|
909
|
+
*
|
|
910
|
+
* @example
|
|
911
|
+
* ```typescript
|
|
912
|
+
* const { executionId, status } = await client.agents.execute('agent-uuid', {
|
|
913
|
+
* task: 'Summarize the latest news about AI',
|
|
914
|
+
* });
|
|
915
|
+
* ```
|
|
916
|
+
*/
|
|
917
|
+
async execute(uuid, input) {
|
|
918
|
+
const idempotencyKey = input.options?.idempotencyKey ?? generateIdempotencyKey();
|
|
919
|
+
return this.httpPost(
|
|
920
|
+
`/${uuid}/execute`,
|
|
921
|
+
{
|
|
922
|
+
task: input.task,
|
|
923
|
+
context: input.context,
|
|
924
|
+
options: input.options
|
|
925
|
+
},
|
|
926
|
+
{ idempotencyKey }
|
|
927
|
+
);
|
|
928
|
+
}
|
|
929
|
+
/**
|
|
930
|
+
* Execute an agent and wait for completion (sync)
|
|
931
|
+
*
|
|
932
|
+
* Polls the execution status until completion or failure.
|
|
933
|
+
*
|
|
934
|
+
* @param uuid - Agent UUID
|
|
935
|
+
* @param input - Execution input
|
|
936
|
+
* @param pollInterval - Polling interval in ms (default: 1000)
|
|
937
|
+
* @returns Final execution result
|
|
938
|
+
*
|
|
939
|
+
* @example
|
|
940
|
+
* ```typescript
|
|
941
|
+
* const execution = await client.agents.executeSync('agent-uuid', {
|
|
942
|
+
* task: 'Write a haiku about coding',
|
|
943
|
+
* });
|
|
944
|
+
* console.log(execution.output);
|
|
945
|
+
* ```
|
|
946
|
+
*/
|
|
947
|
+
async executeSync(uuid, input, pollInterval = 1e3) {
|
|
948
|
+
const { executionId } = await this.execute(uuid, input);
|
|
949
|
+
return this.pollExecution(executionId, pollInterval);
|
|
950
|
+
}
|
|
951
|
+
/**
|
|
952
|
+
* Stream an agent execution
|
|
953
|
+
*
|
|
954
|
+
* Returns a StreamController for real-time event handling.
|
|
955
|
+
*
|
|
956
|
+
* @param uuid - Agent UUID
|
|
957
|
+
* @param input - Execution input
|
|
958
|
+
* @returns Stream controller for event handling
|
|
959
|
+
*
|
|
960
|
+
* @example
|
|
961
|
+
* ```typescript
|
|
962
|
+
* const stream = await client.agents.stream('agent-uuid', {
|
|
963
|
+
* task: 'Research climate change',
|
|
964
|
+
* });
|
|
965
|
+
*
|
|
966
|
+
* stream.on('log', (log) => console.log(log.title));
|
|
967
|
+
* stream.on('toolCall', ({ toolName }) => console.log(`Calling ${toolName}`));
|
|
968
|
+
* stream.on('complete', ({ execution }) => console.log(execution.output));
|
|
969
|
+
*
|
|
970
|
+
* const result = await stream.wait();
|
|
971
|
+
* ```
|
|
972
|
+
*/
|
|
973
|
+
async stream(uuid, input) {
|
|
974
|
+
const { executionId } = await this.execute(uuid, input);
|
|
975
|
+
const config = this.getStreamConfig();
|
|
976
|
+
const controller = createExecutionStreamController({
|
|
977
|
+
executionId,
|
|
978
|
+
baseUrl: config.baseUrl,
|
|
979
|
+
apiKey: config.apiKey,
|
|
980
|
+
orgId: config.orgId,
|
|
981
|
+
getExecution: (id) => this.getExecution(id)
|
|
982
|
+
});
|
|
983
|
+
await controller.connect();
|
|
984
|
+
return controller;
|
|
985
|
+
}
|
|
986
|
+
// ===== RECEIVE Operations =====
|
|
987
|
+
/**
|
|
988
|
+
* Get execution result by ID
|
|
989
|
+
*
|
|
990
|
+
* @param executionId - Execution UUID
|
|
991
|
+
* @returns Execution details including status, output, logs
|
|
992
|
+
*
|
|
993
|
+
* @example
|
|
994
|
+
* ```typescript
|
|
995
|
+
* const execution = await client.agents.getExecution('exec-uuid');
|
|
996
|
+
* if (execution.status === 'completed') {
|
|
997
|
+
* console.log(execution.output);
|
|
998
|
+
* }
|
|
999
|
+
* ```
|
|
1000
|
+
*/
|
|
1001
|
+
async getExecution(executionId) {
|
|
1002
|
+
return this.http.get(`/executions/${executionId}`);
|
|
1003
|
+
}
|
|
1004
|
+
// ===== EDIT Operations =====
|
|
1005
|
+
/**
|
|
1006
|
+
* Update agent details
|
|
1007
|
+
*
|
|
1008
|
+
* @param uuid - Agent UUID
|
|
1009
|
+
* @param data - Fields to update
|
|
1010
|
+
* @returns Updated agent
|
|
1011
|
+
*
|
|
1012
|
+
* @example
|
|
1013
|
+
* ```typescript
|
|
1014
|
+
* const agent = await client.agents.update('agent-uuid', {
|
|
1015
|
+
* name: 'My Updated Agent',
|
|
1016
|
+
* description: 'New description',
|
|
1017
|
+
* });
|
|
1018
|
+
* ```
|
|
1019
|
+
*/
|
|
1020
|
+
async update(uuid, data) {
|
|
1021
|
+
const idempotencyKey = generateIdempotencyKey();
|
|
1022
|
+
return this.httpPatch(`/${uuid}`, data, { idempotencyKey });
|
|
1023
|
+
}
|
|
1024
|
+
/**
|
|
1025
|
+
* Update agent configuration
|
|
1026
|
+
*
|
|
1027
|
+
* @param uuid - Agent UUID
|
|
1028
|
+
* @param config - Configuration fields to update
|
|
1029
|
+
* @returns Updated agent
|
|
1030
|
+
*
|
|
1031
|
+
* @example
|
|
1032
|
+
* ```typescript
|
|
1033
|
+
* const agent = await client.agents.updateConfig('agent-uuid', {
|
|
1034
|
+
* temperature: 0.7,
|
|
1035
|
+
* maxIterations: 5,
|
|
1036
|
+
* });
|
|
1037
|
+
* ```
|
|
1038
|
+
*/
|
|
1039
|
+
async updateConfig(uuid, config) {
|
|
1040
|
+
const idempotencyKey = generateIdempotencyKey();
|
|
1041
|
+
return this.httpPatch(`/${uuid}/config`, config, { idempotencyKey });
|
|
1042
|
+
}
|
|
1043
|
+
/**
|
|
1044
|
+
* Cancel a running execution
|
|
1045
|
+
*
|
|
1046
|
+
* @param executionId - Execution UUID
|
|
1047
|
+
* @returns Updated execution with cancelled status
|
|
1048
|
+
*
|
|
1049
|
+
* @example
|
|
1050
|
+
* ```typescript
|
|
1051
|
+
* const execution = await client.agents.cancelExecution('exec-uuid');
|
|
1052
|
+
* console.log(execution.status); // 'cancelled'
|
|
1053
|
+
* ```
|
|
1054
|
+
*/
|
|
1055
|
+
async cancelExecution(executionId) {
|
|
1056
|
+
return this.http.post(
|
|
1057
|
+
`/executions/${executionId}/cancel`,
|
|
1058
|
+
void 0,
|
|
1059
|
+
{ skipRetry: true }
|
|
1060
|
+
);
|
|
1061
|
+
}
|
|
1062
|
+
// ===== Private helpers =====
|
|
1063
|
+
/**
|
|
1064
|
+
* Poll execution until completion
|
|
1065
|
+
*/
|
|
1066
|
+
async pollExecution(executionId, pollInterval) {
|
|
1067
|
+
while (true) {
|
|
1068
|
+
const execution = await this.getExecution(executionId);
|
|
1069
|
+
if (execution.status === "completed" || execution.status === "failed" || execution.status === "cancelled") {
|
|
1070
|
+
return execution;
|
|
1071
|
+
}
|
|
1072
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
};
|
|
1076
|
+
|
|
1077
|
+
// src/resources/skills.ts
|
|
1078
|
+
var SkillsAPI = class extends BaseResourceAPI {
|
|
1079
|
+
constructor(http) {
|
|
1080
|
+
super(http, "/skills");
|
|
1081
|
+
}
|
|
1082
|
+
// ===== LIST Operations =====
|
|
1083
|
+
/**
|
|
1084
|
+
* List all skills in the organization
|
|
1085
|
+
*
|
|
1086
|
+
* @param options - List options (pagination, filtering by category/tags)
|
|
1087
|
+
* @returns Paginated list of skills
|
|
1088
|
+
*
|
|
1089
|
+
* @example
|
|
1090
|
+
* ```typescript
|
|
1091
|
+
* const { data: skills } = await client.skills.list({
|
|
1092
|
+
* category: 'writing',
|
|
1093
|
+
* tags: ['seo', 'blog'],
|
|
1094
|
+
* });
|
|
1095
|
+
* ```
|
|
1096
|
+
*/
|
|
1097
|
+
async list(options) {
|
|
1098
|
+
const query = {
|
|
1099
|
+
...this.buildListQuery(options),
|
|
1100
|
+
category: options?.category,
|
|
1101
|
+
tags: options?.tags?.join(",")
|
|
1102
|
+
};
|
|
1103
|
+
return this.httpGet("", query);
|
|
1104
|
+
}
|
|
1105
|
+
/**
|
|
1106
|
+
* Get a single skill by UUID with full details
|
|
1107
|
+
*
|
|
1108
|
+
* @param uuid - Skill UUID
|
|
1109
|
+
* @returns Skill with prompt template and tools
|
|
1110
|
+
*
|
|
1111
|
+
* @example
|
|
1112
|
+
* ```typescript
|
|
1113
|
+
* const skill = await client.skills.get('skill-uuid');
|
|
1114
|
+
* console.log(skill.promptTemplate);
|
|
1115
|
+
* ```
|
|
1116
|
+
*/
|
|
1117
|
+
async get(uuid) {
|
|
1118
|
+
return this.httpGet(`/${uuid}`);
|
|
1119
|
+
}
|
|
1120
|
+
/**
|
|
1121
|
+
* Get tools associated with a skill
|
|
1122
|
+
*
|
|
1123
|
+
* @param uuid - Skill UUID
|
|
1124
|
+
* @returns Array of tools used by the skill
|
|
1125
|
+
*
|
|
1126
|
+
* @example
|
|
1127
|
+
* ```typescript
|
|
1128
|
+
* const tools = await client.skills.getTools('skill-uuid');
|
|
1129
|
+
* tools.forEach(tool => console.log(tool.name));
|
|
1130
|
+
* ```
|
|
1131
|
+
*/
|
|
1132
|
+
async getTools(uuid) {
|
|
1133
|
+
return this.httpGet(`/${uuid}/tools`);
|
|
1134
|
+
}
|
|
1135
|
+
// ===== EXECUTE Operations =====
|
|
1136
|
+
/**
|
|
1137
|
+
* Execute a skill with variables
|
|
1138
|
+
*
|
|
1139
|
+
* @param uuid - Skill UUID
|
|
1140
|
+
* @param input - Variables and context for execution
|
|
1141
|
+
* @returns Skill execution result
|
|
1142
|
+
*
|
|
1143
|
+
* @example
|
|
1144
|
+
* ```typescript
|
|
1145
|
+
* const result = await client.skills.execute('skill-uuid', {
|
|
1146
|
+
* variables: {
|
|
1147
|
+
* topic: 'AI in healthcare',
|
|
1148
|
+
* tone: 'professional',
|
|
1149
|
+
* },
|
|
1150
|
+
* });
|
|
1151
|
+
* console.log(result.output);
|
|
1152
|
+
* ```
|
|
1153
|
+
*/
|
|
1154
|
+
async execute(uuid, input) {
|
|
1155
|
+
const idempotencyKey = generateIdempotencyKey();
|
|
1156
|
+
return this.httpPost(
|
|
1157
|
+
`/${uuid}/execute`,
|
|
1158
|
+
{
|
|
1159
|
+
variables: input.variables,
|
|
1160
|
+
context: input.context
|
|
1161
|
+
},
|
|
1162
|
+
{ idempotencyKey }
|
|
1163
|
+
);
|
|
1164
|
+
}
|
|
1165
|
+
// ===== RECEIVE Operations =====
|
|
1166
|
+
/**
|
|
1167
|
+
* Get skill execution result by ID
|
|
1168
|
+
*
|
|
1169
|
+
* @param executionId - Execution UUID
|
|
1170
|
+
* @returns Skill execution details
|
|
1171
|
+
*
|
|
1172
|
+
* @example
|
|
1173
|
+
* ```typescript
|
|
1174
|
+
* const execution = await client.skills.getExecution('exec-uuid');
|
|
1175
|
+
* ```
|
|
1176
|
+
*/
|
|
1177
|
+
async getExecution(executionId) {
|
|
1178
|
+
return this.http.get(`/executions/${executionId}`);
|
|
1179
|
+
}
|
|
1180
|
+
// ===== EDIT Operations =====
|
|
1181
|
+
/**
|
|
1182
|
+
* Update skill details
|
|
1183
|
+
*
|
|
1184
|
+
* @param uuid - Skill UUID
|
|
1185
|
+
* @param data - Fields to update
|
|
1186
|
+
* @returns Updated skill
|
|
1187
|
+
*
|
|
1188
|
+
* @example
|
|
1189
|
+
* ```typescript
|
|
1190
|
+
* const skill = await client.skills.update('skill-uuid', {
|
|
1191
|
+
* name: 'Updated Skill Name',
|
|
1192
|
+
* tags: ['new-tag'],
|
|
1193
|
+
* });
|
|
1194
|
+
* ```
|
|
1195
|
+
*/
|
|
1196
|
+
async update(uuid, data) {
|
|
1197
|
+
const idempotencyKey = generateIdempotencyKey();
|
|
1198
|
+
return this.httpPatch(`/${uuid}`, data, { idempotencyKey });
|
|
1199
|
+
}
|
|
1200
|
+
/**
|
|
1201
|
+
* Update skill prompt template
|
|
1202
|
+
*
|
|
1203
|
+
* @param uuid - Skill UUID
|
|
1204
|
+
* @param prompt - New prompt template
|
|
1205
|
+
* @returns Updated skill with new version
|
|
1206
|
+
*
|
|
1207
|
+
* @example
|
|
1208
|
+
* ```typescript
|
|
1209
|
+
* const skill = await client.skills.updatePrompt('skill-uuid',
|
|
1210
|
+
* 'Write a {{tone}} article about {{topic}}...'
|
|
1211
|
+
* );
|
|
1212
|
+
* console.log(skill.version); // Version incremented
|
|
1213
|
+
* ```
|
|
1214
|
+
*/
|
|
1215
|
+
async updatePrompt(uuid, prompt) {
|
|
1216
|
+
const idempotencyKey = generateIdempotencyKey();
|
|
1217
|
+
return this.httpPatch(`/${uuid}/prompt`, { promptTemplate: prompt }, { idempotencyKey });
|
|
1218
|
+
}
|
|
1219
|
+
};
|
|
1220
|
+
|
|
1221
|
+
// src/resources/tools.ts
|
|
1222
|
+
var ToolsAPI = class extends BaseResourceAPI {
|
|
1223
|
+
constructor(http) {
|
|
1224
|
+
super(http, "/tools");
|
|
1225
|
+
}
|
|
1226
|
+
// ===== LIST Operations =====
|
|
1227
|
+
/**
|
|
1228
|
+
* List all tools in the organization
|
|
1229
|
+
*
|
|
1230
|
+
* @param options - List options (pagination, filtering)
|
|
1231
|
+
* @returns Paginated list of tools
|
|
1232
|
+
*
|
|
1233
|
+
* @example
|
|
1234
|
+
* ```typescript
|
|
1235
|
+
* const { data: tools } = await client.tools.list({
|
|
1236
|
+
* category: 'data',
|
|
1237
|
+
* isEnabled: true,
|
|
1238
|
+
* });
|
|
1239
|
+
* ```
|
|
1240
|
+
*/
|
|
1241
|
+
async list(options) {
|
|
1242
|
+
const query = {
|
|
1243
|
+
...this.buildListQuery(options),
|
|
1244
|
+
category: options?.category,
|
|
1245
|
+
isEnabled: options?.isEnabled
|
|
1246
|
+
};
|
|
1247
|
+
return this.httpGet("", query);
|
|
1248
|
+
}
|
|
1249
|
+
/**
|
|
1250
|
+
* Get a single tool by UUID with schema
|
|
1251
|
+
*
|
|
1252
|
+
* @param uuid - Tool UUID
|
|
1253
|
+
* @returns Tool with input/output schemas
|
|
1254
|
+
*
|
|
1255
|
+
* @example
|
|
1256
|
+
* ```typescript
|
|
1257
|
+
* const tool = await client.tools.get('tool-uuid');
|
|
1258
|
+
* console.log(tool.inputSchema);
|
|
1259
|
+
* ```
|
|
1260
|
+
*/
|
|
1261
|
+
async get(uuid) {
|
|
1262
|
+
return this.httpGet(`/${uuid}`);
|
|
1263
|
+
}
|
|
1264
|
+
// ===== EXECUTE Operations =====
|
|
1265
|
+
/**
|
|
1266
|
+
* Execute a tool directly
|
|
1267
|
+
*
|
|
1268
|
+
* @param uuid - Tool UUID
|
|
1269
|
+
* @param input - Tool input (validated against inputSchema)
|
|
1270
|
+
* @returns Tool execution result
|
|
1271
|
+
*
|
|
1272
|
+
* @example
|
|
1273
|
+
* ```typescript
|
|
1274
|
+
* const result = await client.tools.execute('tool-uuid', {
|
|
1275
|
+
* query: 'weather in London',
|
|
1276
|
+
* limit: 5,
|
|
1277
|
+
* });
|
|
1278
|
+
* console.log(result.output);
|
|
1279
|
+
* ```
|
|
1280
|
+
*/
|
|
1281
|
+
async execute(uuid, input) {
|
|
1282
|
+
const idempotencyKey = generateIdempotencyKey();
|
|
1283
|
+
return this.httpPost(`/${uuid}/execute`, { input }, { idempotencyKey });
|
|
1284
|
+
}
|
|
1285
|
+
/**
|
|
1286
|
+
* Validate input against tool schema
|
|
1287
|
+
*
|
|
1288
|
+
* @param uuid - Tool UUID
|
|
1289
|
+
* @param input - Input to validate
|
|
1290
|
+
* @returns Validation result with errors if invalid
|
|
1291
|
+
*
|
|
1292
|
+
* @example
|
|
1293
|
+
* ```typescript
|
|
1294
|
+
* const validation = await client.tools.validateInput('tool-uuid', {
|
|
1295
|
+
* query: 'test',
|
|
1296
|
+
* });
|
|
1297
|
+
* if (!validation.valid) {
|
|
1298
|
+
* console.log(validation.errors);
|
|
1299
|
+
* }
|
|
1300
|
+
* ```
|
|
1301
|
+
*/
|
|
1302
|
+
async validateInput(uuid, input) {
|
|
1303
|
+
return this.httpPost(`/${uuid}/validate`, { input }, { skipRetry: false });
|
|
1304
|
+
}
|
|
1305
|
+
// ===== RECEIVE Operations =====
|
|
1306
|
+
/**
|
|
1307
|
+
* Get tool execution result by ID
|
|
1308
|
+
*
|
|
1309
|
+
* @param executionId - Execution UUID
|
|
1310
|
+
* @returns Tool execution details
|
|
1311
|
+
*
|
|
1312
|
+
* @example
|
|
1313
|
+
* ```typescript
|
|
1314
|
+
* const execution = await client.tools.getExecution('exec-uuid');
|
|
1315
|
+
* ```
|
|
1316
|
+
*/
|
|
1317
|
+
async getExecution(executionId) {
|
|
1318
|
+
return this.http.get(`/executions/${executionId}`);
|
|
1319
|
+
}
|
|
1320
|
+
// ===== EDIT Operations =====
|
|
1321
|
+
/**
|
|
1322
|
+
* Update tool details
|
|
1323
|
+
*
|
|
1324
|
+
* @param uuid - Tool UUID
|
|
1325
|
+
* @param data - Fields to update
|
|
1326
|
+
* @returns Updated tool
|
|
1327
|
+
*
|
|
1328
|
+
* @example
|
|
1329
|
+
* ```typescript
|
|
1330
|
+
* const tool = await client.tools.update('tool-uuid', {
|
|
1331
|
+
* name: 'Updated Tool Name',
|
|
1332
|
+
* description: 'New description',
|
|
1333
|
+
* });
|
|
1334
|
+
* ```
|
|
1335
|
+
*/
|
|
1336
|
+
async update(uuid, data) {
|
|
1337
|
+
const idempotencyKey = generateIdempotencyKey();
|
|
1338
|
+
return this.httpPatch(`/${uuid}`, data, { idempotencyKey });
|
|
1339
|
+
}
|
|
1340
|
+
/**
|
|
1341
|
+
* Update tool configuration
|
|
1342
|
+
*
|
|
1343
|
+
* @param uuid - Tool UUID
|
|
1344
|
+
* @param config - Configuration to update
|
|
1345
|
+
* @returns Updated tool
|
|
1346
|
+
*
|
|
1347
|
+
* @example
|
|
1348
|
+
* ```typescript
|
|
1349
|
+
* const tool = await client.tools.updateConfig('tool-uuid', {
|
|
1350
|
+
* isEnabled: false,
|
|
1351
|
+
* config: { apiKey: 'new-key' },
|
|
1352
|
+
* });
|
|
1353
|
+
* ```
|
|
1354
|
+
*/
|
|
1355
|
+
async updateConfig(uuid, config) {
|
|
1356
|
+
const idempotencyKey = generateIdempotencyKey();
|
|
1357
|
+
return this.httpPatch(`/${uuid}/config`, config, { idempotencyKey });
|
|
1358
|
+
}
|
|
1359
|
+
};
|
|
1360
|
+
|
|
1361
|
+
// src/resources/artifacts.ts
|
|
1362
|
+
var ArtifactsAPI = class extends BaseResourceAPI {
|
|
1363
|
+
constructor(http) {
|
|
1364
|
+
super(http, "/artifacts");
|
|
1365
|
+
}
|
|
1366
|
+
// ===== LIST Operations =====
|
|
1367
|
+
/**
|
|
1368
|
+
* List artifacts for an execution
|
|
1369
|
+
*
|
|
1370
|
+
* @param executionId - Execution UUID
|
|
1371
|
+
* @param options - List options (pagination, filtering by type)
|
|
1372
|
+
* @returns Paginated list of artifacts
|
|
1373
|
+
*
|
|
1374
|
+
* @example
|
|
1375
|
+
* ```typescript
|
|
1376
|
+
* const { data: artifacts } = await client.artifacts.list('exec-uuid', {
|
|
1377
|
+
* type: 'file',
|
|
1378
|
+
* });
|
|
1379
|
+
* ```
|
|
1380
|
+
*/
|
|
1381
|
+
async list(executionId, options) {
|
|
1382
|
+
const query = {
|
|
1383
|
+
...this.buildListQuery(options),
|
|
1384
|
+
type: options?.type
|
|
1385
|
+
};
|
|
1386
|
+
return this.http.get(`/executions/${executionId}/artifacts`, query);
|
|
1387
|
+
}
|
|
1388
|
+
/**
|
|
1389
|
+
* Get artifact metadata by UUID
|
|
1390
|
+
*
|
|
1391
|
+
* @param uuid - Artifact UUID
|
|
1392
|
+
* @returns Artifact metadata
|
|
1393
|
+
*
|
|
1394
|
+
* @example
|
|
1395
|
+
* ```typescript
|
|
1396
|
+
* const artifact = await client.artifacts.get('artifact-uuid');
|
|
1397
|
+
* console.log(artifact.name, artifact.size);
|
|
1398
|
+
* ```
|
|
1399
|
+
*/
|
|
1400
|
+
async get(uuid) {
|
|
1401
|
+
return this.httpGet(`/${uuid}`);
|
|
1402
|
+
}
|
|
1403
|
+
// ===== RECEIVE Operations =====
|
|
1404
|
+
/**
|
|
1405
|
+
* Download artifact content
|
|
1406
|
+
*
|
|
1407
|
+
* In Node.js returns Buffer, in browser returns Blob.
|
|
1408
|
+
*
|
|
1409
|
+
* @param uuid - Artifact UUID
|
|
1410
|
+
* @returns Artifact content as Buffer (Node.js) or Blob (browser)
|
|
1411
|
+
*
|
|
1412
|
+
* @example
|
|
1413
|
+
* ```typescript
|
|
1414
|
+
* const content = await client.artifacts.download('artifact-uuid');
|
|
1415
|
+
* // Node.js: Buffer
|
|
1416
|
+
* // Browser: Blob
|
|
1417
|
+
* ```
|
|
1418
|
+
*/
|
|
1419
|
+
async download(uuid) {
|
|
1420
|
+
const response = await this.http.request({
|
|
1421
|
+
method: "GET",
|
|
1422
|
+
path: `${this.basePath}/${uuid}/download`,
|
|
1423
|
+
headers: {
|
|
1424
|
+
"Accept": "*/*"
|
|
1425
|
+
}
|
|
1426
|
+
});
|
|
1427
|
+
if (typeof window !== "undefined") {
|
|
1428
|
+
return response.blob();
|
|
1429
|
+
} else {
|
|
1430
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
1431
|
+
return Buffer.from(arrayBuffer);
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
/**
|
|
1435
|
+
* Download artifact as a stream
|
|
1436
|
+
*
|
|
1437
|
+
* In Node.js returns Readable stream, in browser returns ReadableStream.
|
|
1438
|
+
*
|
|
1439
|
+
* @param uuid - Artifact UUID
|
|
1440
|
+
* @returns Readable stream
|
|
1441
|
+
*
|
|
1442
|
+
* @example
|
|
1443
|
+
* ```typescript
|
|
1444
|
+
* const stream = await client.artifacts.downloadStream('artifact-uuid');
|
|
1445
|
+
* // Pipe to file or process incrementally
|
|
1446
|
+
* ```
|
|
1447
|
+
*/
|
|
1448
|
+
async downloadStream(uuid) {
|
|
1449
|
+
const response = await this.http.request({
|
|
1450
|
+
method: "GET",
|
|
1451
|
+
path: `${this.basePath}/${uuid}/stream`,
|
|
1452
|
+
headers: {
|
|
1453
|
+
"Accept": "*/*"
|
|
1454
|
+
}
|
|
1455
|
+
});
|
|
1456
|
+
if (!response.body) {
|
|
1457
|
+
throw new Error("Response body is not available");
|
|
1458
|
+
}
|
|
1459
|
+
return response.body;
|
|
1460
|
+
}
|
|
1461
|
+
/**
|
|
1462
|
+
* Get a signed URL for direct download
|
|
1463
|
+
*
|
|
1464
|
+
* @param uuid - Artifact UUID
|
|
1465
|
+
* @param options - Options including expiration time
|
|
1466
|
+
* @returns Signed URL and expiration time
|
|
1467
|
+
*
|
|
1468
|
+
* @example
|
|
1469
|
+
* ```typescript
|
|
1470
|
+
* const { url, expiresAt } = await client.artifacts.getSignedUrl('artifact-uuid', {
|
|
1471
|
+
* expiresIn: 3600, // 1 hour
|
|
1472
|
+
* });
|
|
1473
|
+
* // Use URL for direct download
|
|
1474
|
+
* ```
|
|
1475
|
+
*/
|
|
1476
|
+
async getSignedUrl(uuid, options) {
|
|
1477
|
+
return this.httpPost(`/${uuid}/signed-url`, {
|
|
1478
|
+
expiresIn: options?.expiresIn ?? 3600
|
|
1479
|
+
});
|
|
1480
|
+
}
|
|
1481
|
+
// ===== EDIT Operations =====
|
|
1482
|
+
/**
|
|
1483
|
+
* Upload a new artifact for an execution
|
|
1484
|
+
*
|
|
1485
|
+
* @param executionId - Execution UUID
|
|
1486
|
+
* @param input - Upload input (name, content, mime type)
|
|
1487
|
+
* @returns Created artifact metadata
|
|
1488
|
+
*
|
|
1489
|
+
* @example
|
|
1490
|
+
* ```typescript
|
|
1491
|
+
* const artifact = await client.artifacts.upload('exec-uuid', {
|
|
1492
|
+
* name: 'report.pdf',
|
|
1493
|
+
* content: fileBuffer,
|
|
1494
|
+
* mimeType: 'application/pdf',
|
|
1495
|
+
* });
|
|
1496
|
+
* ```
|
|
1497
|
+
*/
|
|
1498
|
+
async upload(executionId, input) {
|
|
1499
|
+
const formData = new FormData();
|
|
1500
|
+
if (input.content instanceof Blob) {
|
|
1501
|
+
formData.append("file", input.content, input.name);
|
|
1502
|
+
} else if (typeof Buffer !== "undefined" && Buffer.isBuffer(input.content)) {
|
|
1503
|
+
const arrayBuffer = input.content.buffer.slice(
|
|
1504
|
+
input.content.byteOffset,
|
|
1505
|
+
input.content.byteOffset + input.content.byteLength
|
|
1506
|
+
);
|
|
1507
|
+
const blob = new Blob([arrayBuffer], { type: input.mimeType ?? "application/octet-stream" });
|
|
1508
|
+
formData.append("file", blob, input.name);
|
|
1509
|
+
} else if (input.content instanceof ReadableStream) {
|
|
1510
|
+
const chunks = [];
|
|
1511
|
+
const reader = input.content.getReader();
|
|
1512
|
+
while (true) {
|
|
1513
|
+
const { done, value } = await reader.read();
|
|
1514
|
+
if (done) break;
|
|
1515
|
+
const arrayBuffer = value.buffer.slice(
|
|
1516
|
+
value.byteOffset,
|
|
1517
|
+
value.byteOffset + value.byteLength
|
|
1518
|
+
);
|
|
1519
|
+
chunks.push(arrayBuffer);
|
|
1520
|
+
}
|
|
1521
|
+
const blob = new Blob(chunks, { type: input.mimeType ?? "application/octet-stream" });
|
|
1522
|
+
formData.append("file", blob, input.name);
|
|
1523
|
+
}
|
|
1524
|
+
if (input.type) {
|
|
1525
|
+
formData.append("type", input.type);
|
|
1526
|
+
}
|
|
1527
|
+
if (input.metadata) {
|
|
1528
|
+
formData.append("metadata", JSON.stringify(input.metadata));
|
|
1529
|
+
}
|
|
1530
|
+
return this.http.request({
|
|
1531
|
+
method: "POST",
|
|
1532
|
+
path: `/executions/${executionId}/artifacts`,
|
|
1533
|
+
body: formData,
|
|
1534
|
+
headers: {
|
|
1535
|
+
// Remove Content-Type to let fetch set it with proper boundary
|
|
1536
|
+
}
|
|
1537
|
+
});
|
|
1538
|
+
}
|
|
1539
|
+
/**
|
|
1540
|
+
* Delete an artifact
|
|
1541
|
+
*
|
|
1542
|
+
* @param uuid - Artifact UUID
|
|
1543
|
+
*
|
|
1544
|
+
* @example
|
|
1545
|
+
* ```typescript
|
|
1546
|
+
* await client.artifacts.delete('artifact-uuid');
|
|
1547
|
+
* ```
|
|
1548
|
+
*/
|
|
1549
|
+
async delete(uuid) {
|
|
1550
|
+
return this.httpDelete(`/${uuid}`);
|
|
1551
|
+
}
|
|
1552
|
+
};
|
|
1553
|
+
|
|
1554
|
+
// src/resources/sessions.ts
|
|
1555
|
+
var SessionsAPI = class extends BaseResourceAPI {
|
|
1556
|
+
constructor(http, getStreamConfig) {
|
|
1557
|
+
super(http, "/sessions");
|
|
1558
|
+
this.getStreamConfig = getStreamConfig;
|
|
1559
|
+
}
|
|
1560
|
+
// ===== LIST Operations =====
|
|
1561
|
+
/**
|
|
1562
|
+
* List all sessions in the organization
|
|
1563
|
+
*
|
|
1564
|
+
* @param options - List options (pagination, filtering by agent)
|
|
1565
|
+
* @returns Paginated list of sessions
|
|
1566
|
+
*
|
|
1567
|
+
* @example
|
|
1568
|
+
* ```typescript
|
|
1569
|
+
* const { data: sessions } = await client.sessions.list({
|
|
1570
|
+
* agentUuid: 'agent-uuid',
|
|
1571
|
+
* });
|
|
1572
|
+
* ```
|
|
1573
|
+
*/
|
|
1574
|
+
async list(options) {
|
|
1575
|
+
const query = {
|
|
1576
|
+
...this.buildListQuery(options),
|
|
1577
|
+
agentUuid: options?.agentUuid
|
|
1578
|
+
};
|
|
1579
|
+
return this.httpGet("", query);
|
|
1580
|
+
}
|
|
1581
|
+
/**
|
|
1582
|
+
* Get session details by ID
|
|
1583
|
+
*
|
|
1584
|
+
* @param sessionId - Session ID
|
|
1585
|
+
* @returns Session details
|
|
1586
|
+
*
|
|
1587
|
+
* @example
|
|
1588
|
+
* ```typescript
|
|
1589
|
+
* const session = await client.sessions.get('session-id');
|
|
1590
|
+
* console.log(session.messageCount);
|
|
1591
|
+
* ```
|
|
1592
|
+
*/
|
|
1593
|
+
async get(sessionId) {
|
|
1594
|
+
return this.httpGet(`/${sessionId}`);
|
|
1595
|
+
}
|
|
1596
|
+
// ===== EXECUTE Operations =====
|
|
1597
|
+
/**
|
|
1598
|
+
* Send a message to a session
|
|
1599
|
+
*
|
|
1600
|
+
* Triggers an agent execution in the context of the session.
|
|
1601
|
+
* Returns immediately with execution ID. Use getHistory() to get
|
|
1602
|
+
* the response, or use stream() for real-time updates.
|
|
1603
|
+
*
|
|
1604
|
+
* @param sessionId - Session ID
|
|
1605
|
+
* @param input - Message content and optional context
|
|
1606
|
+
* @returns Execution ID and status
|
|
1607
|
+
*
|
|
1608
|
+
* @example
|
|
1609
|
+
* ```typescript
|
|
1610
|
+
* const { executionId } = await client.sessions.sendMessage('session-id', {
|
|
1611
|
+
* message: 'What is the capital of France?',
|
|
1612
|
+
* });
|
|
1613
|
+
* ```
|
|
1614
|
+
*/
|
|
1615
|
+
async sendMessage(sessionId, input) {
|
|
1616
|
+
const idempotencyKey = generateIdempotencyKey();
|
|
1617
|
+
return this.httpPost(
|
|
1618
|
+
`/${sessionId}/messages`,
|
|
1619
|
+
{
|
|
1620
|
+
message: input.message,
|
|
1621
|
+
context: input.context
|
|
1622
|
+
},
|
|
1623
|
+
{ idempotencyKey }
|
|
1624
|
+
);
|
|
1625
|
+
}
|
|
1626
|
+
/**
|
|
1627
|
+
* Send a message and wait for response (sync)
|
|
1628
|
+
*
|
|
1629
|
+
* @param sessionId - Session ID
|
|
1630
|
+
* @param input - Message content and optional context
|
|
1631
|
+
* @param pollInterval - Polling interval in ms (default: 1000)
|
|
1632
|
+
* @returns Final execution result
|
|
1633
|
+
*
|
|
1634
|
+
* @example
|
|
1635
|
+
* ```typescript
|
|
1636
|
+
* const execution = await client.sessions.sendMessageSync('session-id', {
|
|
1637
|
+
* message: 'What is the capital of France?',
|
|
1638
|
+
* });
|
|
1639
|
+
* console.log(execution.output);
|
|
1640
|
+
* ```
|
|
1641
|
+
*/
|
|
1642
|
+
async sendMessageSync(sessionId, input, pollInterval = 1e3) {
|
|
1643
|
+
const { executionId } = await this.sendMessage(sessionId, input);
|
|
1644
|
+
return this.pollExecution(executionId, pollInterval);
|
|
1645
|
+
}
|
|
1646
|
+
/**
|
|
1647
|
+
* Stream a message response
|
|
1648
|
+
*
|
|
1649
|
+
* Returns a StreamController for real-time event handling.
|
|
1650
|
+
*
|
|
1651
|
+
* @param sessionId - Session ID
|
|
1652
|
+
* @param input - Message content and optional context
|
|
1653
|
+
* @returns Stream controller
|
|
1654
|
+
*
|
|
1655
|
+
* @example
|
|
1656
|
+
* ```typescript
|
|
1657
|
+
* const stream = await client.sessions.stream('session-id', {
|
|
1658
|
+
* message: 'Tell me more about that',
|
|
1659
|
+
* });
|
|
1660
|
+
*
|
|
1661
|
+
* stream.on('log', (log) => console.log(log.title));
|
|
1662
|
+
* stream.on('complete', ({ execution }) => console.log(execution.output));
|
|
1663
|
+
*
|
|
1664
|
+
* const result = await stream.wait();
|
|
1665
|
+
* ```
|
|
1666
|
+
*/
|
|
1667
|
+
async stream(sessionId, input) {
|
|
1668
|
+
const { executionId } = await this.sendMessage(sessionId, input);
|
|
1669
|
+
const config = this.getStreamConfig();
|
|
1670
|
+
const controller = createExecutionStreamController({
|
|
1671
|
+
executionId,
|
|
1672
|
+
baseUrl: config.baseUrl,
|
|
1673
|
+
apiKey: config.apiKey,
|
|
1674
|
+
orgId: config.orgId,
|
|
1675
|
+
getExecution: (id) => this.getExecution(id)
|
|
1676
|
+
});
|
|
1677
|
+
await controller.connect();
|
|
1678
|
+
return controller;
|
|
1679
|
+
}
|
|
1680
|
+
// ===== RECEIVE Operations =====
|
|
1681
|
+
/**
|
|
1682
|
+
* Get session conversation history
|
|
1683
|
+
*
|
|
1684
|
+
* @param sessionId - Session ID
|
|
1685
|
+
* @returns Session with all messages
|
|
1686
|
+
*
|
|
1687
|
+
* @example
|
|
1688
|
+
* ```typescript
|
|
1689
|
+
* const history = await client.sessions.getHistory('session-id');
|
|
1690
|
+
* history.messages.forEach(msg => {
|
|
1691
|
+
* console.log(`${msg.role}: ${msg.content}`);
|
|
1692
|
+
* });
|
|
1693
|
+
* ```
|
|
1694
|
+
*/
|
|
1695
|
+
async getHistory(sessionId) {
|
|
1696
|
+
return this.httpGet(`/${sessionId}/history`);
|
|
1697
|
+
}
|
|
1698
|
+
/**
|
|
1699
|
+
* List artifacts for a session
|
|
1700
|
+
*
|
|
1701
|
+
* Returns all artifacts generated across all executions in the session.
|
|
1702
|
+
* Useful for retrieving images, files, and other outputs created during
|
|
1703
|
+
* agent interactions.
|
|
1704
|
+
*
|
|
1705
|
+
* @param sessionId - Session ID
|
|
1706
|
+
* @param options - List options (filtering by type, pagination)
|
|
1707
|
+
* @returns Paginated list of session artifacts
|
|
1708
|
+
*
|
|
1709
|
+
* @example
|
|
1710
|
+
* ```typescript
|
|
1711
|
+
* // Get all images from a session
|
|
1712
|
+
* const { data: artifacts } = await client.sessions.listArtifacts('session-id', {
|
|
1713
|
+
* type: 'image',
|
|
1714
|
+
* });
|
|
1715
|
+
*
|
|
1716
|
+
* artifacts.forEach(artifact => {
|
|
1717
|
+
* console.log(artifact.filename, artifact.url);
|
|
1718
|
+
* });
|
|
1719
|
+
* ```
|
|
1720
|
+
*/
|
|
1721
|
+
async listArtifacts(sessionId, options) {
|
|
1722
|
+
const query = {
|
|
1723
|
+
...this.buildListQuery(options),
|
|
1724
|
+
type: options?.type,
|
|
1725
|
+
includeVariants: options?.includeVariants
|
|
1726
|
+
};
|
|
1727
|
+
return this.httpGet(`/${sessionId}/artifacts`, query);
|
|
1728
|
+
}
|
|
1729
|
+
/**
|
|
1730
|
+
* Get execution result
|
|
1731
|
+
*/
|
|
1732
|
+
async getExecution(executionId) {
|
|
1733
|
+
return this.http.get(`/executions/${executionId}`);
|
|
1734
|
+
}
|
|
1735
|
+
// ===== EDIT Operations =====
|
|
1736
|
+
/**
|
|
1737
|
+
* Create a new session for an agent
|
|
1738
|
+
*
|
|
1739
|
+
* @param agentUuid - Agent UUID to associate with session
|
|
1740
|
+
* @param options - Optional system message
|
|
1741
|
+
* @returns Created session
|
|
1742
|
+
*
|
|
1743
|
+
* @example
|
|
1744
|
+
* ```typescript
|
|
1745
|
+
* const session = await client.sessions.create({
|
|
1746
|
+
* agentUuid: 'agent-uuid',
|
|
1747
|
+
* systemMessage: 'You are a helpful assistant.',
|
|
1748
|
+
* });
|
|
1749
|
+
* console.log(session.id);
|
|
1750
|
+
* ```
|
|
1751
|
+
*/
|
|
1752
|
+
async create(input) {
|
|
1753
|
+
const idempotencyKey = generateIdempotencyKey();
|
|
1754
|
+
return this.httpPost("", input, { idempotencyKey });
|
|
1755
|
+
}
|
|
1756
|
+
/**
|
|
1757
|
+
* Delete a session and all its messages
|
|
1758
|
+
*
|
|
1759
|
+
* @param sessionId - Session ID
|
|
1760
|
+
*
|
|
1761
|
+
* @example
|
|
1762
|
+
* ```typescript
|
|
1763
|
+
* await client.sessions.delete('session-id');
|
|
1764
|
+
* ```
|
|
1765
|
+
*/
|
|
1766
|
+
async delete(sessionId) {
|
|
1767
|
+
return this.httpDelete(`/${sessionId}`);
|
|
1768
|
+
}
|
|
1769
|
+
// ===== Private helpers =====
|
|
1770
|
+
/**
|
|
1771
|
+
* Poll execution until completion
|
|
1772
|
+
*/
|
|
1773
|
+
async pollExecution(executionId, pollInterval) {
|
|
1774
|
+
while (true) {
|
|
1775
|
+
const execution = await this.getExecution(executionId);
|
|
1776
|
+
if (execution.status === "completed" || execution.status === "failed" || execution.status === "cancelled") {
|
|
1777
|
+
return execution;
|
|
1778
|
+
}
|
|
1779
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
};
|
|
1783
|
+
|
|
1784
|
+
// src/client.ts
|
|
1785
|
+
var DEFAULT_BASE_URL = "https://api.aisaas.com/v1";
|
|
1786
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
1787
|
+
var AISaaSClient = class {
|
|
1788
|
+
httpClient;
|
|
1789
|
+
config;
|
|
1790
|
+
/**
|
|
1791
|
+
* Agent operations (list, execute, stream, update)
|
|
1792
|
+
*/
|
|
1793
|
+
agents;
|
|
1794
|
+
/**
|
|
1795
|
+
* Skill operations (list, get, execute, update)
|
|
1796
|
+
*/
|
|
1797
|
+
skills;
|
|
1798
|
+
/**
|
|
1799
|
+
* Tool operations (list, get, execute, validate, update)
|
|
1800
|
+
*/
|
|
1801
|
+
tools;
|
|
1802
|
+
/**
|
|
1803
|
+
* Artifact operations (list, get, download, upload, delete)
|
|
1804
|
+
*/
|
|
1805
|
+
artifacts;
|
|
1806
|
+
/**
|
|
1807
|
+
* Session operations (list, get, create, message, delete)
|
|
1808
|
+
*/
|
|
1809
|
+
sessions;
|
|
1810
|
+
/**
|
|
1811
|
+
* Create a new AI SaaS client
|
|
1812
|
+
*
|
|
1813
|
+
* @param options - Client configuration options
|
|
1814
|
+
*
|
|
1815
|
+
* @example
|
|
1816
|
+
* ```typescript
|
|
1817
|
+
* // API key authentication
|
|
1818
|
+
* const client = new AISaaSClient({
|
|
1819
|
+
* apiKey: 'sk_...',
|
|
1820
|
+
* orgId: 123,
|
|
1821
|
+
* });
|
|
1822
|
+
*
|
|
1823
|
+
* // OAuth token authentication
|
|
1824
|
+
* const client = new AISaaSClient({
|
|
1825
|
+
* token: 'eyJ...',
|
|
1826
|
+
* orgId: 123,
|
|
1827
|
+
* });
|
|
1828
|
+
*
|
|
1829
|
+
* // Token provider (for automatic refresh)
|
|
1830
|
+
* const client = new AISaaSClient({
|
|
1831
|
+
* tokenProvider: async () => myAuth.getAccessToken(),
|
|
1832
|
+
* orgId: 123,
|
|
1833
|
+
* });
|
|
1834
|
+
* ```
|
|
1835
|
+
*/
|
|
1836
|
+
constructor(options) {
|
|
1837
|
+
this.validateOptions(options);
|
|
1838
|
+
this.config = {
|
|
1839
|
+
baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,
|
|
1840
|
+
orgId: options.orgId,
|
|
1841
|
+
timeout: options.timeout ?? DEFAULT_TIMEOUT,
|
|
1842
|
+
headers: options.headers
|
|
1843
|
+
};
|
|
1844
|
+
if ("apiKey" in options) {
|
|
1845
|
+
this.config.apiKey = options.apiKey;
|
|
1846
|
+
} else if ("token" in options) {
|
|
1847
|
+
this.config.token = options.token;
|
|
1848
|
+
} else if ("tokenProvider" in options) {
|
|
1849
|
+
this.config.tokenProvider = options.tokenProvider;
|
|
1850
|
+
}
|
|
1851
|
+
const retryConfig = {
|
|
1852
|
+
...DEFAULT_RETRY_CONFIG,
|
|
1853
|
+
maxRetries: options.maxRetries ?? DEFAULT_RETRY_CONFIG.maxRetries
|
|
1854
|
+
};
|
|
1855
|
+
const httpConfig = {
|
|
1856
|
+
baseUrl: this.config.baseUrl,
|
|
1857
|
+
apiKey: this.config.apiKey,
|
|
1858
|
+
token: this.config.token,
|
|
1859
|
+
tokenProvider: this.config.tokenProvider,
|
|
1860
|
+
orgId: this.config.orgId,
|
|
1861
|
+
timeout: this.config.timeout,
|
|
1862
|
+
retry: retryConfig,
|
|
1863
|
+
headers: this.config.headers
|
|
1864
|
+
};
|
|
1865
|
+
this.httpClient = new HttpClient(httpConfig);
|
|
1866
|
+
const getStreamConfig = () => ({
|
|
1867
|
+
baseUrl: this.config.baseUrl,
|
|
1868
|
+
apiKey: this.config.apiKey,
|
|
1869
|
+
token: this.config.token,
|
|
1870
|
+
orgId: this.config.orgId
|
|
1871
|
+
});
|
|
1872
|
+
this.agents = new AgentsAPI(this.httpClient, getStreamConfig);
|
|
1873
|
+
this.skills = new SkillsAPI(this.httpClient);
|
|
1874
|
+
this.tools = new ToolsAPI(this.httpClient);
|
|
1875
|
+
this.artifacts = new ArtifactsAPI(this.httpClient);
|
|
1876
|
+
this.sessions = new SessionsAPI(this.httpClient, getStreamConfig);
|
|
1877
|
+
}
|
|
1878
|
+
/**
|
|
1879
|
+
* Validate client options
|
|
1880
|
+
*/
|
|
1881
|
+
validateOptions(options) {
|
|
1882
|
+
const hasApiKey = "apiKey" in options && options.apiKey;
|
|
1883
|
+
const hasToken = "token" in options && options.token;
|
|
1884
|
+
const hasTokenProvider = "tokenProvider" in options && options.tokenProvider;
|
|
1885
|
+
if (!hasApiKey && !hasToken && !hasTokenProvider) {
|
|
1886
|
+
throw new Error(
|
|
1887
|
+
"Authentication required. Provide apiKey, token, or tokenProvider."
|
|
1888
|
+
);
|
|
1889
|
+
}
|
|
1890
|
+
if (options.orgId === void 0 || options.orgId === null) {
|
|
1891
|
+
throw new Error("Organization ID (orgId) is required.");
|
|
1892
|
+
}
|
|
1893
|
+
if (typeof options.orgId !== "number") {
|
|
1894
|
+
throw new Error("Organization ID (orgId) must be a number.");
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
};
|
|
1898
|
+
|
|
1899
|
+
export { AISaaSClient, AISaaSError, AuthenticationError, AuthorizationError, ConflictError, NetworkError, NotFoundError, RateLimitError, ServerError, TimeoutError, ValidationError };
|
|
1900
|
+
//# sourceMappingURL=index.js.map
|
|
1901
|
+
//# sourceMappingURL=index.js.map
|