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