@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.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