@meistrari/tela-sdk-js 2.4.3 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -21,15 +21,14 @@ function _interopNamespaceCompat(e) {
21
21
 
22
22
  const changeCase__namespace = /*#__PURE__*/_interopNamespaceCompat(changeCase);
23
23
  const z__default = /*#__PURE__*/_interopDefaultCompat(z);
24
- const z__namespace = /*#__PURE__*/_interopNamespaceCompat(z);
25
24
  const Emittery__default = /*#__PURE__*/_interopDefaultCompat(Emittery);
26
25
 
27
- const version = "2.4.3";
26
+ const version = "2.6.0";
28
27
 
29
- var __defProp$7 = Object.defineProperty;
30
- var __defNormalProp$7 = (obj, key, value) => key in obj ? __defProp$7(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
31
- var __publicField$7 = (obj, key, value) => {
32
- __defNormalProp$7(obj, typeof key !== "symbol" ? key + "" : key, value);
28
+ var __defProp$a = Object.defineProperty;
29
+ var __defNormalProp$a = (obj, key, value) => key in obj ? __defProp$a(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
30
+ var __publicField$a = (obj, key, value) => {
31
+ __defNormalProp$a(obj, typeof key !== "symbol" ? key + "" : key, value);
33
32
  return value;
34
33
  };
35
34
  class TelaError extends Error {
@@ -57,7 +56,7 @@ class InvalidFileURL extends TelaError {
57
56
  class FileUploadError extends TelaError {
58
57
  constructor(message, statusCode) {
59
58
  super(`Failed to upload file: ${message} (Status code: ${statusCode})`);
60
- __publicField$7(this, "statusCode");
59
+ __publicField$a(this, "statusCode");
61
60
  this.statusCode = statusCode;
62
61
  }
63
62
  }
@@ -74,16 +73,30 @@ class InvalidExecutionModeError extends TelaError {
74
73
  class ExecutionFailedError extends TelaError {
75
74
  constructor(rawOutput) {
76
75
  super(`Execution failed: ${JSON.stringify(rawOutput)}`);
77
- __publicField$7(this, "rawOutput");
76
+ __publicField$a(this, "rawOutput");
78
77
  this.rawOutput = rawOutput;
79
78
  }
80
79
  }
80
+ class TaskFailedError extends TelaError {
81
+ constructor(rawTask, message, cause) {
82
+ super(`Task failed: ${JSON.stringify(rawTask)}`, { cause });
83
+ __publicField$a(this, "rawTask");
84
+ this.rawTask = rawTask;
85
+ }
86
+ }
87
+ class BatchExecutionFailedError extends TelaError {
88
+ constructor(rawResponse) {
89
+ super(`Batch execution failed: ${JSON.stringify(rawResponse)}`);
90
+ __publicField$a(this, "rawResponse");
91
+ this.rawResponse = rawResponse;
92
+ }
93
+ }
81
94
  class APIError extends TelaError {
82
95
  constructor(statusCode, error, _message) {
83
96
  const message = error?.message ? typeof error.message === "string" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : _message;
84
97
  super(message);
85
- __publicField$7(this, "statusCode");
86
- __publicField$7(this, "error");
98
+ __publicField$a(this, "statusCode");
99
+ __publicField$a(this, "error");
87
100
  this.statusCode = statusCode;
88
101
  this.error = error;
89
102
  }
@@ -125,7 +138,7 @@ class APIError extends TelaError {
125
138
  class UserAbortError extends APIError {
126
139
  constructor({ message } = {}) {
127
140
  super(void 0, void 0, message || "User aborted.");
128
- __publicField$7(this, "statusCode");
141
+ __publicField$a(this, "statusCode");
129
142
  }
130
143
  }
131
144
  class ConnectionError extends APIError {
@@ -134,7 +147,7 @@ class ConnectionError extends APIError {
134
147
  cause
135
148
  }) {
136
149
  super(void 0, void 0, message || "Connection error.");
137
- __publicField$7(this, "statusCode");
150
+ __publicField$a(this, "statusCode");
138
151
  if (cause)
139
152
  this.cause = cause;
140
153
  }
@@ -144,57 +157,57 @@ class ConnectionTimeout extends APIError {
144
157
  message
145
158
  } = {}) {
146
159
  super(void 0, void 0, message || "Request timed out.");
147
- __publicField$7(this, "statusCode");
160
+ __publicField$a(this, "statusCode");
148
161
  }
149
162
  }
150
163
  class BadRequestError extends APIError {
151
164
  constructor() {
152
165
  super(...arguments);
153
- __publicField$7(this, "statusCode", 400);
166
+ __publicField$a(this, "statusCode", 400);
154
167
  }
155
168
  // todo: handle validation errors from zod/typebox
156
169
  }
157
170
  class AuthenticationError extends APIError {
158
171
  constructor() {
159
172
  super(...arguments);
160
- __publicField$7(this, "statusCode", 401);
173
+ __publicField$a(this, "statusCode", 401);
161
174
  }
162
175
  }
163
176
  class AuthorizationError extends APIError {
164
177
  constructor() {
165
178
  super(...arguments);
166
- __publicField$7(this, "statusCode", 403);
179
+ __publicField$a(this, "statusCode", 403);
167
180
  }
168
181
  }
169
182
  class NotFoundError extends APIError {
170
183
  constructor() {
171
184
  super(...arguments);
172
- __publicField$7(this, "statusCode", 404);
185
+ __publicField$a(this, "statusCode", 404);
173
186
  }
174
187
  }
175
188
  class ConflictError extends APIError {
176
189
  constructor() {
177
190
  super(...arguments);
178
- __publicField$7(this, "statusCode", 409);
191
+ __publicField$a(this, "statusCode", 409);
179
192
  }
180
193
  }
181
194
  class UnprocessableEntityError extends APIError {
182
195
  constructor() {
183
196
  super(...arguments);
184
197
  // todo: check if tela returns 400 or 422 for zod errors
185
- __publicField$7(this, "statusCode", 422);
198
+ __publicField$a(this, "statusCode", 422);
186
199
  }
187
200
  }
188
201
  class RateLimitError extends APIError {
189
202
  constructor() {
190
203
  super(...arguments);
191
- __publicField$7(this, "statusCode", 429);
204
+ __publicField$a(this, "statusCode", 429);
192
205
  }
193
206
  }
194
207
  class InternalServerError extends APIError {
195
208
  constructor() {
196
209
  super(...arguments);
197
- __publicField$7(this, "statusCode", 500);
210
+ __publicField$a(this, "statusCode", 500);
198
211
  }
199
212
  }
200
213
  function toError(err) {
@@ -305,11 +318,38 @@ function transformObjectFromSnakeCaseToCamelCase(obj, exclusions = []) {
305
318
  }
306
319
  return result;
307
320
  }
321
+ const DURATION_REGEX = /(?<amount>\d+)(?<unit>[smhd])/;
322
+ const DURATION_UNITS = {
323
+ s: 1e3,
324
+ // 1 second in milliseconds
325
+ m: 6e4,
326
+ // 1 minute in milliseconds
327
+ h: 36e5,
328
+ // 1 hour in milliseconds
329
+ d: 864e5
330
+ // 1 day in milliseconds
331
+ };
332
+ function transformDurationToMs(durationStr) {
333
+ if (!durationStr) {
334
+ return void 0;
335
+ }
336
+ if (typeof durationStr === "number") {
337
+ return durationStr;
338
+ }
339
+ const match = durationStr.match(DURATION_REGEX);
340
+ const amount = match?.groups?.amount;
341
+ const unit = match?.groups?.unit;
342
+ const multiplier = DURATION_UNITS[unit];
343
+ if (!amount || Number.isNaN(Number.parseInt(amount)) || !multiplier) {
344
+ return void 0;
345
+ }
346
+ return Number.parseInt(amount) * multiplier;
347
+ }
308
348
 
309
- var __defProp$6 = Object.defineProperty;
310
- var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
311
- var __publicField$6 = (obj, key, value) => {
312
- __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
349
+ var __defProp$9 = Object.defineProperty;
350
+ var __defNormalProp$9 = (obj, key, value) => key in obj ? __defProp$9(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
351
+ var __publicField$9 = (obj, key, value) => {
352
+ __defNormalProp$9(obj, typeof key !== "symbol" ? key + "" : key, value);
313
353
  return value;
314
354
  };
315
355
  class Stream {
@@ -573,9 +613,9 @@ function findDoubleNewlineIndex(buffer) {
573
613
  }
574
614
  class SSEDecoder {
575
615
  constructor() {
576
- __publicField$6(this, "data");
577
- __publicField$6(this, "event");
578
- __publicField$6(this, "chunks");
616
+ __publicField$9(this, "data");
617
+ __publicField$9(this, "event");
618
+ __publicField$9(this, "chunks");
579
619
  this.event = null;
580
620
  this.data = [];
581
621
  this.chunks = [];
@@ -616,9 +656,9 @@ class SSEDecoder {
616
656
  const _LineDecoder = class _LineDecoder {
617
657
  // TextDecoder found in browsers; not typed to avoid pulling in either "dom" or "node" types.
618
658
  constructor() {
619
- __publicField$6(this, "buffer");
620
- __publicField$6(this, "trailingCR");
621
- __publicField$6(this, "textDecoder");
659
+ __publicField$9(this, "buffer");
660
+ __publicField$9(this, "trailingCR");
661
+ __publicField$9(this, "textDecoder");
622
662
  this.buffer = [];
623
663
  this.trailingCR = false;
624
664
  }
@@ -693,8 +733,8 @@ const _LineDecoder = class _LineDecoder {
693
733
  }
694
734
  };
695
735
  // prettier-ignore
696
- __publicField$6(_LineDecoder, "NEWLINE_CHARS", /* @__PURE__ */ new Set(["\n", "\r"]));
697
- __publicField$6(_LineDecoder, "NEWLINE_REGEXP", /\r\n|[\n\r]/g);
736
+ __publicField$9(_LineDecoder, "NEWLINE_CHARS", /* @__PURE__ */ new Set(["\n", "\r"]));
737
+ __publicField$9(_LineDecoder, "NEWLINE_REGEXP", /\r\n|[\n\r]/g);
698
738
  let LineDecoder = _LineDecoder;
699
739
  function partition(str, delimiter) {
700
740
  const index = str.indexOf(delimiter);
@@ -731,10 +771,10 @@ function readableStreamAsyncIterable(stream) {
731
771
  };
732
772
  }
733
773
 
734
- var __defProp$5 = Object.defineProperty;
735
- var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
736
- var __publicField$5 = (obj, key, value) => {
737
- __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
774
+ var __defProp$8 = Object.defineProperty;
775
+ var __defNormalProp$8 = (obj, key, value) => key in obj ? __defProp$8(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
776
+ var __publicField$8 = (obj, key, value) => {
777
+ __defNormalProp$8(obj, typeof key !== "symbol" ? key + "" : key, value);
738
778
  return value;
739
779
  };
740
780
  function getRequestIdFromResponse(response) {
@@ -776,6 +816,7 @@ function getRequestIdFromResponse(response) {
776
816
  }
777
817
  async function defaultParseResponse(props) {
778
818
  const { response } = props;
819
+ const { transformCase = true } = props.options;
779
820
  if (props.options.stream) {
780
821
  debug("response", response.status, response.url, response.headers, response.body);
781
822
  return Stream.fromSSEResponse(response, props.controller);
@@ -789,22 +830,30 @@ async function defaultParseResponse(props) {
789
830
  const json = await response.json();
790
831
  debug("response", response.status, response.url, response.headers, json);
791
832
  const requestId = getRequestIdFromResponse(response);
792
- const finalJson = { ...json };
793
833
  if (requestId) {
794
- finalJson.requestId = requestId;
834
+ json.requestId = requestId;
795
835
  }
796
- return transformObjectFromSnakeCaseToCamelCase(finalJson, DEFAULT_FIELDS_TRANSFORMATION_EXCLUSIONS);
836
+ return transformCase ? transformObjectFromSnakeCaseToCamelCase(json, DEFAULT_FIELDS_TRANSFORMATION_EXCLUSIONS) : json;
797
837
  }
798
838
  const text = await response.text();
799
839
  debug("response", response.status, response.url, response.headers, text);
800
840
  return text;
801
841
  }
842
+ function transformObjectCase(obj, transformCase) {
843
+ if (!obj) {
844
+ return obj;
845
+ }
846
+ if (transformCase) {
847
+ return transformObjectFromCamelCaseToSnakeCase(obj, DEFAULT_FIELDS_TRANSFORMATION_EXCLUSIONS);
848
+ }
849
+ return obj;
850
+ }
802
851
  class BaseClient {
803
852
  constructor({ baseURL, maxRetries = 5, timeout = 0 }) {
804
- __publicField$5(this, "baseURL");
805
- __publicField$5(this, "maxRetries");
806
- __publicField$5(this, "timeout");
807
- __publicField$5(this, "fetch");
853
+ __publicField$8(this, "baseURL");
854
+ __publicField$8(this, "maxRetries");
855
+ __publicField$8(this, "timeout");
856
+ __publicField$8(this, "fetch");
808
857
  this.baseURL = baseURL;
809
858
  this.maxRetries = validateMaxRetries(maxRetries);
810
859
  this.timeout = validateTimeout(timeout);
@@ -843,10 +892,11 @@ class BaseClient {
843
892
  return this.methodRequest("DELETE", path, opts);
844
893
  }
845
894
  async methodRequest(method, path, opts) {
895
+ const { transformCase = true } = opts ?? {};
846
896
  const headers = this.createHeaders();
847
897
  debug("methodRequest", method, path, opts);
848
- const transformedQuery = opts?.query ? transformObjectFromCamelCaseToSnakeCase(opts.query, DEFAULT_FIELDS_TRANSFORMATION_EXCLUSIONS) : void 0;
849
- const transformedBody = opts?.body ? transformObjectFromCamelCaseToSnakeCase(opts.body, DEFAULT_FIELDS_TRANSFORMATION_EXCLUSIONS) : void 0;
898
+ const transformedQuery = transformObjectCase(opts?.query, transformCase);
899
+ const transformedBody = transformObjectCase(opts?.body, transformCase);
850
900
  const { response, options, controller } = await this.request({
851
901
  method,
852
902
  path,
@@ -1027,6 +1077,9 @@ class BaseClient {
1027
1077
  if (value === null) {
1028
1078
  return `${encodeURIComponent(key)}=`;
1029
1079
  }
1080
+ if (Array.isArray(value)) {
1081
+ return value.map((item) => `${encodeURIComponent(key)}[]=${encodeURIComponent(item)}`).join("&");
1082
+ }
1030
1083
  throw new TelaError(
1031
1084
  `Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`
1032
1085
  );
@@ -1080,10 +1133,10 @@ async function getStreamSize(stream) {
1080
1133
  return size;
1081
1134
  }
1082
1135
 
1083
- var __defProp$4 = Object.defineProperty;
1084
- var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1085
- var __publicField$4 = (obj, key, value) => {
1086
- __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
1136
+ var __defProp$7 = Object.defineProperty;
1137
+ var __defNormalProp$7 = (obj, key, value) => key in obj ? __defProp$7(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1138
+ var __publicField$7 = (obj, key, value) => {
1139
+ __defNormalProp$7(obj, typeof key !== "symbol" ? key + "" : key, value);
1087
1140
  return value;
1088
1141
  };
1089
1142
  function TelaFileSchema() {
@@ -1091,11 +1144,11 @@ function TelaFileSchema() {
1091
1144
  }
1092
1145
  class TelaFile {
1093
1146
  constructor(file, options = {}) {
1094
- __publicField$4(this, "_file");
1095
- __publicField$4(this, "_options");
1096
- __publicField$4(this, "_size", null);
1097
- __publicField$4(this, "_mimeType");
1098
- __publicField$4(this, "_name");
1147
+ __publicField$7(this, "_file");
1148
+ __publicField$7(this, "_options");
1149
+ __publicField$7(this, "_size", null);
1150
+ __publicField$7(this, "_mimeType");
1151
+ __publicField$7(this, "_name");
1099
1152
  this._file = file;
1100
1153
  if (file instanceof File || file instanceof Blob) {
1101
1154
  this._size = file.size;
@@ -1241,7 +1294,17 @@ class TelaFile {
1241
1294
  return url.startsWith("vault://");
1242
1295
  }
1243
1296
  }
1297
+ function isTelaFile(obj) {
1298
+ return obj instanceof TelaFile;
1299
+ }
1300
+ function isTelaFileArray(obj) {
1301
+ return Array.isArray(obj) && obj.length > 0 && obj.every(isTelaFile);
1302
+ }
1244
1303
 
1304
+ const zod = {
1305
+ ...z.z,
1306
+ file: TelaFileSchema
1307
+ };
1245
1308
  function compareSchemas(clientSchema, serverSchema, path = "$") {
1246
1309
  const mismatches = [];
1247
1310
  if (clientSchema.type !== serverSchema.type) {
@@ -1398,11 +1461,172 @@ function validateInputSchema(clientSchema, serverVariables) {
1398
1461
  function validateOutputSchema(clientSchema, serverSchema) {
1399
1462
  return compareSchemas(clientSchema, serverSchema);
1400
1463
  }
1464
+ function validateSchemas(resource, input, output, promptVersion) {
1465
+ const canvasIdentifier = `${promptVersion.title} (${promptVersion.promptId})`;
1466
+ if (input instanceof z.z.ZodType) {
1467
+ try {
1468
+ const inputSchema = z.z.toJSONSchema(input, { unrepresentable: "any" });
1469
+ const mismatches = validateInputSchema(inputSchema, promptVersion.variables);
1470
+ if (mismatches.length === 0) {
1471
+ return;
1472
+ }
1473
+ console.warn(
1474
+ `[Tela SDK - ${resource} Input Validation] Input schema mismatches for ${resource} "${canvasIdentifier}":`
1475
+ );
1476
+ for (const mismatch of mismatches) {
1477
+ console.warn(` - ${mismatch.path}: ${mismatch.issue}`);
1478
+ }
1479
+ } catch (error) {
1480
+ console.warn(
1481
+ `[Tela SDK - ${resource} Input Validation] Failed to validate input schema for ${resource} "${canvasIdentifier}":`,
1482
+ error
1483
+ );
1484
+ }
1485
+ }
1486
+ if (output instanceof z.z.ZodType) {
1487
+ try {
1488
+ const outputSchema = z.z.toJSONSchema(output);
1489
+ const serverOutput = promptVersion.configuration.structuredOutput;
1490
+ if (!serverOutput.enabled) {
1491
+ console.warn(
1492
+ `[Tela SDK - ${resource} Output Validation] Output schema provided for ${resource} "${canvasIdentifier}", but structured output is not enabled on the server. The schema may not be enforced.`
1493
+ );
1494
+ return;
1495
+ }
1496
+ const mismatches = validateOutputSchema(outputSchema, serverOutput.schema);
1497
+ if (mismatches.length === 0) {
1498
+ return;
1499
+ }
1500
+ console.warn(
1501
+ `[Tela SDK - ${resource} Output Validation] Output schema mismatches for ${resource} "${canvasIdentifier}":`
1502
+ );
1503
+ for (const mismatch of mismatches) {
1504
+ console.warn(` - ${mismatch.path}: ${mismatch.issue}`);
1505
+ }
1506
+ } catch (error) {
1507
+ console.warn(
1508
+ `[Tela SDK - ${resource} Output Validation] Failed to validate output schema for ${resource} "${canvasIdentifier}":`,
1509
+ error
1510
+ );
1511
+ }
1512
+ }
1513
+ }
1401
1514
 
1402
- var __defProp$3 = Object.defineProperty;
1403
- var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1404
- var __publicField$3 = (obj, key, value) => {
1405
- __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
1515
+ async function calculateSha256sum(content) {
1516
+ const stream = content instanceof File || content instanceof Blob ? content.stream() : content;
1517
+ const reader = stream.getReader();
1518
+ try {
1519
+ const { createHash } = await import('node:crypto');
1520
+ const hash = createHash("sha256");
1521
+ while (true) {
1522
+ const { done, value } = await reader.read();
1523
+ if (done)
1524
+ break;
1525
+ hash.update(value);
1526
+ }
1527
+ return hash.digest("hex");
1528
+ } catch {
1529
+ const chunks = [];
1530
+ while (true) {
1531
+ const { done, value } = await reader.read();
1532
+ if (done)
1533
+ break;
1534
+ chunks.push(value);
1535
+ }
1536
+ const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0);
1537
+ const buffer = new Uint8Array(totalLength);
1538
+ let offset = 0;
1539
+ for (const chunk of chunks) {
1540
+ buffer.set(chunk, offset);
1541
+ offset += chunk.length;
1542
+ }
1543
+ const hashBuffer = await crypto.subtle.digest("SHA-256", buffer);
1544
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
1545
+ const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
1546
+ return hashHex;
1547
+ }
1548
+ }
1549
+
1550
+ async function uploadFile(file, client) {
1551
+ let content = await file.getUploadableContent();
1552
+ let sha256sumStream;
1553
+ if (typeof content === "string") {
1554
+ return { fileUrl: content, options: file.options };
1555
+ }
1556
+ const filename = file.name ?? void 0;
1557
+ const fileType = file.type ?? void 0;
1558
+ const contentLength = file.size ?? void 0;
1559
+ if (content instanceof ReadableStream) {
1560
+ const [hashStream, contentStream] = content.tee();
1561
+ content = contentStream;
1562
+ sha256sumStream = hashStream;
1563
+ }
1564
+ const sha256sum = await calculateSha256sum(sha256sumStream ?? content);
1565
+ const { id, uploadUrl } = await client.post("/_services/vault/files", {
1566
+ body: {
1567
+ fileName: filename,
1568
+ mimeType: fileType,
1569
+ size: contentLength ?? void 0,
1570
+ sha256sum
1571
+ },
1572
+ transformCase: false
1573
+ });
1574
+ if (content instanceof ReadableStream && typeof Bun !== "undefined") {
1575
+ console.warn(
1576
+ "[Tela SDK - WARNING] Buffering file upload due to Bun fetch implementation. Large files may cause memory issues. Consider using Node.js for streaming uploads.",
1577
+ { fileName: filename, fileSize: contentLength }
1578
+ );
1579
+ const chunks = [];
1580
+ const reader = content.getReader();
1581
+ while (true) {
1582
+ const { done, value } = await reader.read();
1583
+ if (done)
1584
+ break;
1585
+ chunks.push(value);
1586
+ }
1587
+ content = new Blob(chunks, { type: fileType ?? "application/octet-stream" });
1588
+ }
1589
+ const request = new Request(uploadUrl, {
1590
+ method: "PUT",
1591
+ body: content,
1592
+ headers: {
1593
+ "Content-Type": fileType ?? "application/octet-stream",
1594
+ ...file.size ? { "Content-Length": file.size.toString() } : {}
1595
+ }
1596
+ });
1597
+ const uploadResponse = await fetch(request);
1598
+ if (!uploadResponse.ok) {
1599
+ throw new FileUploadError(await uploadResponse.text(), uploadResponse.status);
1600
+ }
1601
+ return { fileUrl: `vault://${id}`, options: file.options };
1602
+ }
1603
+ async function uploadFiles(files, client) {
1604
+ const uploadPromises = files.map((file) => uploadFile(file, client));
1605
+ return Promise.all(uploadPromises);
1606
+ }
1607
+ async function downloadFile(vaultReference, client) {
1608
+ const vaultId = vaultReference.replace("vault://", "");
1609
+ const response = await client.get(`/_services/vault/files/${vaultId}`);
1610
+ return fetch(response.url).then((res) => res.blob());
1611
+ }
1612
+ async function streamFile(vaultReference, client) {
1613
+ const vaultId = vaultReference.replace("vault://", "");
1614
+ const response = await client.get(`/_services/vault/files/${vaultId}`);
1615
+ return fetch(response.url).then((res) => {
1616
+ if (!res.ok) {
1617
+ throw new Error("Failed to stream file", { cause: res.statusText });
1618
+ }
1619
+ if (!res.body) {
1620
+ throw new Error("Failed to stream file", { cause: "No body" });
1621
+ }
1622
+ return res.body;
1623
+ });
1624
+ }
1625
+
1626
+ var __defProp$6 = Object.defineProperty;
1627
+ var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1628
+ var __publicField$6 = (obj, key, value) => {
1629
+ __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
1406
1630
  return value;
1407
1631
  };
1408
1632
  function timeout(ms, signal) {
@@ -1418,10 +1642,10 @@ function timeout(ms, signal) {
1418
1642
  }
1419
1643
  class Poller {
1420
1644
  constructor({ interval, timeout: timeout2, abortSignal }) {
1421
- __publicField$3(this, "_interval");
1422
- __publicField$3(this, "_timeout");
1423
- __publicField$3(this, "_abortSignal");
1424
- __publicField$3(this, "_internalAbortController");
1645
+ __publicField$6(this, "_interval");
1646
+ __publicField$6(this, "_timeout");
1647
+ __publicField$6(this, "_abortSignal");
1648
+ __publicField$6(this, "_internalAbortController");
1425
1649
  if (interval <= 0) {
1426
1650
  throw new TelaError("Interval must be greater than 0");
1427
1651
  }
@@ -1467,7 +1691,7 @@ class Poller {
1467
1691
  const resultPromise = async () => {
1468
1692
  try {
1469
1693
  while (!this._abortSignal.aborted) {
1470
- const result = await callback(this._abortSignal);
1694
+ const result = await callback();
1471
1695
  if (result.done) {
1472
1696
  return result.value;
1473
1697
  }
@@ -1482,53 +1706,12 @@ class Poller {
1482
1706
  }
1483
1707
  }
1484
1708
 
1485
- async function calculateSha256sum(content) {
1486
- const stream = content instanceof File || content instanceof Blob ? content.stream() : content;
1487
- const reader = stream.getReader();
1488
- try {
1489
- const { createHash } = await import('node:crypto');
1490
- const hash = createHash("sha256");
1491
- while (true) {
1492
- const { done, value } = await reader.read();
1493
- if (done)
1494
- break;
1495
- hash.update(value);
1496
- }
1497
- return hash.digest("hex");
1498
- } catch {
1499
- const chunks = [];
1500
- while (true) {
1501
- const { done, value } = await reader.read();
1502
- if (done)
1503
- break;
1504
- chunks.push(value);
1505
- }
1506
- const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0);
1507
- const buffer = new Uint8Array(totalLength);
1508
- let offset = 0;
1509
- for (const chunk of chunks) {
1510
- buffer.set(chunk, offset);
1511
- offset += chunk.length;
1512
- }
1513
- const hashBuffer = await crypto.subtle.digest("SHA-256", buffer);
1514
- const hashArray = Array.from(new Uint8Array(hashBuffer));
1515
- const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
1516
- return hashHex;
1517
- }
1518
- }
1519
-
1520
- var __defProp$2 = Object.defineProperty;
1521
- var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1522
- var __publicField$2 = (obj, key, value) => {
1523
- __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
1709
+ var __defProp$5 = Object.defineProperty;
1710
+ var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1711
+ var __publicField$5 = (obj, key, value) => {
1712
+ __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
1524
1713
  return value;
1525
1714
  };
1526
- function isTelaFile(obj) {
1527
- return obj instanceof TelaFile;
1528
- }
1529
- function isTelaFileArray(obj) {
1530
- return Array.isArray(obj) && obj.length > 0 && obj.every(isTelaFile);
1531
- }
1532
1715
  function isUUID(str) {
1533
1716
  const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1534
1717
  return uuidRegex.test(str);
@@ -1560,6 +1743,17 @@ function getResultFromPollingResponse(response) {
1560
1743
  }
1561
1744
  throw new Error("Invalid response type");
1562
1745
  }
1746
+ function normalizeExecutionStatus(status) {
1747
+ switch (status) {
1748
+ case "completed":
1749
+ case "validating":
1750
+ return "succeeded";
1751
+ case "cancelled":
1752
+ return "failed";
1753
+ default:
1754
+ return status;
1755
+ }
1756
+ }
1563
1757
  class CanvasExecution extends Emittery__default {
1564
1758
  /**
1565
1759
  * Creates a new canvas execution instance.
@@ -1571,20 +1765,20 @@ class CanvasExecution extends Emittery__default {
1571
1765
  */
1572
1766
  constructor(variables, params = { async: false }, outputSchema, client, isTask = false) {
1573
1767
  super();
1574
- __publicField$2(this, "_id");
1575
- __publicField$2(this, "_status");
1576
- __publicField$2(this, "_variables");
1577
- __publicField$2(this, "_params");
1578
- __publicField$2(this, "_client");
1579
- __publicField$2(this, "_outputSchema");
1580
- __publicField$2(this, "_skipResultValidation");
1581
- __publicField$2(this, "_abortController");
1582
- __publicField$2(this, "_isTask");
1583
- __publicField$2(this, "_resultPromise");
1584
- __publicField$2(this, "_stream");
1585
- __publicField$2(this, "_rawResultValue");
1586
- __publicField$2(this, "_requestId");
1587
- __publicField$2(this, "_task");
1768
+ __publicField$5(this, "_id");
1769
+ __publicField$5(this, "_status");
1770
+ __publicField$5(this, "_variables");
1771
+ __publicField$5(this, "_params");
1772
+ __publicField$5(this, "_client");
1773
+ __publicField$5(this, "_outputSchema");
1774
+ __publicField$5(this, "_skipResultValidation");
1775
+ __publicField$5(this, "_abortController");
1776
+ __publicField$5(this, "_isTask");
1777
+ __publicField$5(this, "_resultPromise");
1778
+ __publicField$5(this, "_stream");
1779
+ __publicField$5(this, "_rawResultValue");
1780
+ __publicField$5(this, "_requestId");
1781
+ __publicField$5(this, "_task");
1588
1782
  this._variables = variables;
1589
1783
  this._params = params;
1590
1784
  this._outputSchema = outputSchema;
@@ -2090,13 +2284,13 @@ class CanvasExecution extends Emittery__default {
2090
2284
  const resolvedVariables = await this.resolveVariables();
2091
2285
  return await this.create(resolvedVariables, { async: true }).then((response) => {
2092
2286
  this._id = "completionRunId" in response ? response.completionRunId : response.id;
2093
- this.status = response.status;
2287
+ this.status = normalizeExecutionStatus(response.status);
2094
2288
  if (this._isTask) {
2095
2289
  this._task = response;
2096
2290
  }
2097
2291
  this.emit("poll", {
2098
2292
  id: response.id,
2099
- status: response.status,
2293
+ status: normalizeExecutionStatus(response.status),
2100
2294
  outputContent: response.outputContent,
2101
2295
  rawOutput: "rawOutput" in response ? response.rawOutput : void 0,
2102
2296
  requestId: response.requestId
@@ -2129,27 +2323,27 @@ class CanvasExecution extends Emittery__default {
2129
2323
  throw new InvalidExecutionModeError("Polling is only supported for async executions");
2130
2324
  }
2131
2325
  return new Poller({
2132
- interval: this._params.pollingInterval ?? 1e3,
2326
+ interval: transformDurationToMs(this._params.pollingInterval) ?? 1e3,
2133
2327
  // 1 second
2134
- timeout: this._params.pollingTimeout ?? 6e4,
2328
+ timeout: transformDurationToMs(this._params.pollingTimeout) ?? 6e4,
2135
2329
  // 1 minute
2136
2330
  abortSignal: this._abortController.signal
2137
- }).start(async (signal) => {
2331
+ }).start(async () => {
2138
2332
  const response = await this._client.get(
2139
2333
  `/v2/chat/completions/${this.id}`,
2140
2334
  {
2141
- signal
2335
+ signal: this._abortController.signal
2142
2336
  }
2143
2337
  );
2144
- this.status = response.status;
2338
+ this.status = normalizeExecutionStatus(response.status);
2145
2339
  this.emit("poll", response);
2146
- if (response.status === "failed") {
2340
+ if (this.status === "failed") {
2147
2341
  const error = new ExecutionFailedError(response.rawOutput);
2148
2342
  this.cancel();
2149
2343
  this.emit("error", error);
2150
2344
  throw error;
2151
2345
  }
2152
- if (response.status !== "succeeded") {
2346
+ if (this.status !== "succeeded") {
2153
2347
  return {
2154
2348
  done: false,
2155
2349
  value: void 0
@@ -2158,7 +2352,7 @@ class CanvasExecution extends Emittery__default {
2158
2352
  this._rawResultValue = response;
2159
2353
  this.emit("success", { ...getResultFromPollingResponse(response), requestId: response?.requestId });
2160
2354
  return {
2161
- done: response.status === "succeeded",
2355
+ done: this.status === "succeeded",
2162
2356
  value: getResultFromPollingResponse(response)
2163
2357
  };
2164
2358
  }).then((value) => {
@@ -2167,7 +2361,7 @@ class CanvasExecution extends Emittery__default {
2167
2361
  }
2168
2362
  return this._outputSchema.parse(value);
2169
2363
  }).catch((error) => {
2170
- if (this._status !== "failed") {
2364
+ if (this.status !== "failed") {
2171
2365
  this.status = "failed";
2172
2366
  }
2173
2367
  if (this.listenerCount("error") > 0) {
@@ -2196,56 +2390,7 @@ class CanvasExecution extends Emittery__default {
2196
2390
  * ```
2197
2391
  */
2198
2392
  async uploadFile(file) {
2199
- let content = await file.getUploadableContent();
2200
- let sha256sumStream;
2201
- if (typeof content === "string") {
2202
- return { fileUrl: content, options: file.options };
2203
- }
2204
- const filename = file.name ?? void 0;
2205
- const fileType = file.type ?? void 0;
2206
- const contentLength = file.size ?? void 0;
2207
- if (content instanceof ReadableStream) {
2208
- const [hashStream, contentStream] = content.tee();
2209
- content = contentStream;
2210
- sha256sumStream = hashStream;
2211
- }
2212
- const sha256sum = await calculateSha256sum(sha256sumStream ?? content);
2213
- const { id, uploadUrl } = await this._client.post("/_services/vault/files", {
2214
- body: {
2215
- fileName: filename,
2216
- mimeType: fileType,
2217
- size: contentLength ?? void 0,
2218
- sha256sum
2219
- }
2220
- });
2221
- if (content instanceof ReadableStream && typeof Bun !== "undefined") {
2222
- console.warn(
2223
- "[Tela SDK - WARNING] Buffering file upload due to Bun fetch implementation. Large files may cause memory issues. Consider using Node.js for streaming uploads.",
2224
- { fileName: filename, fileSize: contentLength }
2225
- );
2226
- const chunks = [];
2227
- const reader = content.getReader();
2228
- while (true) {
2229
- const { done, value } = await reader.read();
2230
- if (done)
2231
- break;
2232
- chunks.push(value);
2233
- }
2234
- content = new Blob(chunks, { type: fileType ?? "application/octet-stream" });
2235
- }
2236
- const request = new Request(uploadUrl, {
2237
- method: "PUT",
2238
- body: content,
2239
- headers: {
2240
- "Content-Type": fileType ?? "application/octet-stream",
2241
- ...file.size ? { "Content-Length": file.size.toString() } : {}
2242
- }
2243
- });
2244
- const uploadResponse = await fetch(request);
2245
- if (!uploadResponse.ok) {
2246
- throw new FileUploadError(await uploadResponse.text(), uploadResponse.status);
2247
- }
2248
- return { fileUrl: `vault://${id}`, options: file.options };
2393
+ return uploadFile(file, this._client);
2249
2394
  }
2250
2395
  /**
2251
2396
  * Uploads multiple files and returns their URLs and options.
@@ -2262,213 +2407,1516 @@ class CanvasExecution extends Emittery__default {
2262
2407
  }
2263
2408
  }
2264
2409
 
2265
- var __defProp$1 = Object.defineProperty;
2266
- var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
2267
- var __publicField$1 = (obj, key, value) => {
2268
- __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
2410
+ var __defProp$4 = Object.defineProperty;
2411
+ var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
2412
+ var __publicField$4 = (obj, key, value) => {
2413
+ __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
2269
2414
  return value;
2270
2415
  };
2271
- const zod = {
2272
- ...z__namespace,
2273
- file: TelaFileSchema
2274
- };
2275
- function fetchById(id, client) {
2276
- return client.get(`/prompt/${id}/promoted-version`);
2277
- }
2278
- function fetchByVersionId(versionId, client) {
2279
- return client.get(`/prompt-version/${versionId}`);
2280
- }
2281
- function fetchByApplicationId(applicationId, client) {
2282
- return client.get(`/prompt-application/${applicationId}/targetPromptVersion`);
2283
- }
2284
- function fetchByAny({ id, versionId, applicationId, client }) {
2285
- if (applicationId) {
2286
- return fetchByApplicationId(applicationId, client);
2416
+ const BatchResultItem = z__default.looseObject({
2417
+ reference_id: z__default.string(),
2418
+ status: z__default.string(),
2419
+ execution_id: z__default.string(),
2420
+ result: z__default.object({
2421
+ id: z__default.string(),
2422
+ tags: z__default.array(z__default.string()),
2423
+ status: z__default.string(),
2424
+ metadata: z__default.object({
2425
+ promptVersion: z__default.object({
2426
+ modelConfigurations: z__default.object({
2427
+ type: z__default.string(),
2428
+ model: z__default.string(),
2429
+ temperature: z__default.number(),
2430
+ structuredOutput: z__default.object({
2431
+ schema: z__default.looseObject({}).optional(),
2432
+ enabled: z__default.boolean()
2433
+ })
2434
+ }),
2435
+ variablesDefinitions: z__default.array(
2436
+ z__default.object({
2437
+ name: z__default.string(),
2438
+ type: z__default.string(),
2439
+ required: z__default.boolean(),
2440
+ processingOptions: z__default.object({ allowMultimodal: z__default.boolean() })
2441
+ })
2442
+ )
2443
+ })
2444
+ }),
2445
+ promptId: z__default.string(),
2446
+ rawInput: z__default.object({
2447
+ tags: z__default.array(z__default.string()),
2448
+ async: z__default.boolean(),
2449
+ canvas_id: z__default.string(),
2450
+ variables: z__default.looseObject({})
2451
+ }),
2452
+ createdAt: z__default.string(),
2453
+ deletedAt: z__default.null(),
2454
+ rawOutput: z__default.object({
2455
+ id: z__default.string(),
2456
+ usage: z__default.object({
2457
+ cost: z__default.object({
2458
+ total_cost: z__default.number(),
2459
+ prompt_cost: z__default.number(),
2460
+ completion_cost: z__default.number()
2461
+ }),
2462
+ total_tokens: z__default.number(),
2463
+ prompt_tokens: z__default.number(),
2464
+ completion_tokens: z__default.number()
2465
+ }),
2466
+ object: z__default.string(),
2467
+ choices: z__default.array(
2468
+ z__default.object({
2469
+ message: z__default.object({
2470
+ role: z__default.string(),
2471
+ content: z__default.looseObject({}),
2472
+ tool_calls: z__default.array(z__default.object({ type: z__default.string(), function: z__default.object({ name: z__default.string(), arguments: z__default.looseObject({}) }) })),
2473
+ function_call: z__default.null()
2474
+ })
2475
+ })
2476
+ ),
2477
+ created: z__default.number()
2478
+ }),
2479
+ updatedAt: z__default.string(),
2480
+ creditsUsed: z__default.number(),
2481
+ workspaceId: z__default.string(),
2482
+ inputContent: z__default.object({
2483
+ files: z__default.array(z__default.object({ file_url: z__default.string() })),
2484
+ messages: z__default.array(z__default.object({ role: z__default.string(), content: z__default.looseObject({}) })),
2485
+ variables: z__default.looseObject({})
2486
+ }),
2487
+ outputContent: z__default.object({
2488
+ role: z__default.string(),
2489
+ content: z__default.looseObject({}),
2490
+ tool_calls: z__default.array(z__default.looseObject({})),
2491
+ function_call: z__default.string().nullable()
2492
+ }),
2493
+ promptVersionId: z__default.string(),
2494
+ compatibilityDate: z__default.string(),
2495
+ promptApplicationId: z__default.string().nullable()
2496
+ }),
2497
+ error: z__default.null()
2498
+ });
2499
+ class BatchExecutionResult {
2500
+ /**
2501
+ * Creates a new batch execution result wrapper.
2502
+ *
2503
+ * @param client - HTTP client for making API requests.
2504
+ * @param response - Raw batch execution response from the server.
2505
+ * @internal
2506
+ */
2507
+ constructor(client, response) {
2508
+ __publicField$4(this, "_client");
2509
+ __publicField$4(this, "_response");
2510
+ this._client = client;
2511
+ this._response = response;
2287
2512
  }
2288
- if (versionId) {
2289
- return fetchByVersionId(versionId, client);
2513
+ get requestId() {
2514
+ return this._response.requestId;
2290
2515
  }
2291
- if (id) {
2292
- return fetchById(id, client);
2516
+ /**
2517
+ * Gets the unique identifier for this batch execution.
2518
+ *
2519
+ * @returns The batch execution ID.
2520
+ */
2521
+ get id() {
2522
+ return this._response.id;
2523
+ }
2524
+ /**
2525
+ * Gets the current status of the batch execution.
2526
+ *
2527
+ * @returns The batch status.
2528
+ */
2529
+ get status() {
2530
+ return this._response.status;
2531
+ }
2532
+ /**
2533
+ * Gets the progress statistics for this batch.
2534
+ *
2535
+ * @returns Object containing completed, failed, and total execution counts, or null if not available.
2536
+ */
2537
+ get state() {
2538
+ return this._response.state;
2539
+ }
2540
+ /**
2541
+ * Gets the vault URL of the output JSONL file containing all results.
2542
+ *
2543
+ * @returns The output file URL, or null if batch is not completed.
2544
+ */
2545
+ get outputFile() {
2546
+ return this._response.outputFile;
2547
+ }
2548
+ /**
2549
+ * Gets the raw API response without any processing.
2550
+ *
2551
+ * @returns The complete batch response object.
2552
+ */
2553
+ get rawResponse() {
2554
+ return this._response;
2555
+ }
2556
+ /**
2557
+ * Gets the timestamp when this batch was created.
2558
+ *
2559
+ * @returns Creation date.
2560
+ */
2561
+ get createdAt() {
2562
+ return new Date(this._response.createdAt);
2563
+ }
2564
+ /**
2565
+ * Gets the timestamp when this batch was last updated.
2566
+ *
2567
+ * @returns Last update date.
2568
+ */
2569
+ get updatedAt() {
2570
+ return new Date(this._response.updatedAt);
2571
+ }
2572
+ /**
2573
+ * Gets the timestamp when this batch completed successfully.
2574
+ *
2575
+ * @returns Completion date, or null if not completed.
2576
+ */
2577
+ get completedAt() {
2578
+ return this._response.completedAt ? new Date(this._response.completedAt) : null;
2579
+ }
2580
+ /**
2581
+ * Gets the timestamp when this batch was canceled.
2582
+ *
2583
+ * @returns Cancellation date, or null if not canceled.
2584
+ */
2585
+ get canceledAt() {
2586
+ return this._response.canceledAt ? new Date(this._response.canceledAt) : null;
2587
+ }
2588
+ /**
2589
+ * Gets the timestamp when this batch failed.
2590
+ *
2591
+ * @returns Failure date, or null if not failed.
2592
+ */
2593
+ get failedAt() {
2594
+ return this._response.failedAt ? new Date(this._response.failedAt) : null;
2595
+ }
2596
+ /**
2597
+ * Downloads the complete output file as a Blob.
2598
+ *
2599
+ * The output file is a JSONL (JSON Lines) file where each line contains
2600
+ * one execution result with its reference ID, status, and output.
2601
+ *
2602
+ * @throws {Error} If batch is not completed or output file is unavailable.
2603
+ * @returns A promise resolving to the output file as a Blob.
2604
+ *
2605
+ * @example
2606
+ * ```typescript
2607
+ * const file = await result.downloadOutputFile()
2608
+ * const text = await file.text()
2609
+ * console.log(text) // JSONL content
2610
+ * ```
2611
+ */
2612
+ downloadOutputFile() {
2613
+ this.validateOutputFile();
2614
+ return downloadFile(this._response.outputFile, this._client);
2615
+ }
2616
+ /**
2617
+ * Streams the output file as a ReadableStream for memory-efficient processing.
2618
+ *
2619
+ * Useful for large batches where loading the entire file into memory is not practical.
2620
+ *
2621
+ * @throws {Error} If batch is not completed or output file is unavailable.
2622
+ * @returns A promise resolving to a ReadableStream of the output file.
2623
+ *
2624
+ * @example
2625
+ * ```typescript
2626
+ * const stream = await result.streamOutputFile()
2627
+ * // Process stream with custom logic
2628
+ * ```
2629
+ */
2630
+ async streamOutputFile() {
2631
+ this.validateOutputFile();
2632
+ return streamFile(this._response.outputFile, this._client);
2633
+ }
2634
+ /**
2635
+ * Downloads and parses all results into an array.
2636
+ *
2637
+ * Loads the entire output file into memory, parses each line, and extracts
2638
+ * the output content. For large batches, consider using `iterateResults()` instead.
2639
+ *
2640
+ * @throws {Error} If batch is not completed, output file is unavailable, or parsing fails.
2641
+ * @returns A promise resolving to an array of all execution outputs.
2642
+ *
2643
+ * @example
2644
+ * ```typescript
2645
+ * const results = await result.getResults()
2646
+ * console.log(`Got ${results.length} results`)
2647
+ * results.forEach((output, i) => console.log(`Result ${i}:`, output))
2648
+ * ```
2649
+ */
2650
+ async getResults() {
2651
+ const resultFile = await this.downloadOutputFile();
2652
+ const results = await resultFile.text();
2653
+ return results.split("\n").filter((line) => line.trim().length > 0).map((result) => JSON.parse(result)).map((result) => {
2654
+ const parsedResult = BatchResultItem.safeParse(result);
2655
+ if (!parsedResult.success) {
2656
+ throw new Error("Invalid result from the batch API", { cause: parsedResult.error });
2657
+ }
2658
+ return parsedResult.data.result.outputContent.content;
2659
+ });
2660
+ }
2661
+ /**
2662
+ * Asynchronously iterates over raw result items from the output file.
2663
+ *
2664
+ * Streams and parses the output file line-by-line, yielding raw JSON objects.
2665
+ * Each yielded object contains the full result structure including metadata.
2666
+ *
2667
+ * @param params - Iteration options.
2668
+ * @param params.abortController - Optional AbortController to cancel iteration.
2669
+ * @throws {Error} If batch is not completed or output file is unavailable.
2670
+ * @yields Raw result objects from the JSONL file.
2671
+ *
2672
+ * @example
2673
+ * ```typescript
2674
+ * for await (const rawResult of result.iterateRawResults()) {
2675
+ * console.log('Reference ID:', rawResult.reference_id)
2676
+ * console.log('Status:', rawResult.status)
2677
+ * console.log('Output:', rawResult.result.outputContent.content)
2678
+ * }
2679
+ * ```
2680
+ */
2681
+ async *iterateRawResults(params = {}) {
2682
+ const { abortController = new AbortController() } = params;
2683
+ const stream = await this.streamOutputFile();
2684
+ for await (const result of Stream.fromReadableStream(stream, abortController)) {
2685
+ yield result;
2686
+ }
2687
+ }
2688
+ /**
2689
+ * Asynchronously iterates over parsed output content from the batch results.
2690
+ *
2691
+ * Streams and parses the output file line-by-line, yielding only the output content
2692
+ * (not the full result metadata). Memory-efficient for large batches.
2693
+ *
2694
+ * @param params - Iteration options.
2695
+ * @param params.abortController - Optional AbortController to cancel iteration.
2696
+ * @throws {Error} If batch is not completed, output file is unavailable, or parsing fails.
2697
+ * @yields Parsed output content from each execution.
2698
+ *
2699
+ * @example
2700
+ * ```typescript
2701
+ * const controller = new AbortController()
2702
+ *
2703
+ * for await (const output of result.iterateResults({ abortController: controller })) {
2704
+ * console.log(output)
2705
+ * if (someCondition) {
2706
+ * controller.abort() // Stop iteration early
2707
+ * }
2708
+ * }
2709
+ * ```
2710
+ */
2711
+ async *iterateResults(params = {}) {
2712
+ for await (const result of this.iterateRawResults(params)) {
2713
+ const parsedResult = BatchResultItem.safeParse(result);
2714
+ if (!parsedResult.success) {
2715
+ throw new Error("Invalid result from the batch API", { cause: parsedResult.error });
2716
+ }
2717
+ yield parsedResult.data.result.outputContent.content;
2718
+ }
2719
+ }
2720
+ /**
2721
+ * Fetches the raw result metadata for a specific execution by its reference ID.
2722
+ *
2723
+ * Queries the API for the execution result using the reference ID tag.
2724
+ * Returns the complete execution metadata including input, output, and usage statistics.
2725
+ *
2726
+ * @param referenceId - The reference ID of the execution to retrieve.
2727
+ * @throws {Error} If no result found with the given reference ID.
2728
+ * @returns A promise resolving to the raw execution result object.
2729
+ *
2730
+ * @example
2731
+ * ```typescript
2732
+ * const rawResult = await result.getRawResult('my-ref-id')
2733
+ * console.log('Credits used:', rawResult.creditsUsed)
2734
+ * console.log('Execution status:', rawResult.status)
2735
+ * ```
2736
+ */
2737
+ async getRawResult(referenceId) {
2738
+ const response = await this._client.get("/v1/completion-run/", {
2739
+ query: {
2740
+ tags: `reference_id:${referenceId}`
2741
+ }
2742
+ });
2743
+ const result = response.data[0];
2744
+ if (!result) {
2745
+ throw new Error("Result not found");
2746
+ }
2747
+ return result;
2748
+ }
2749
+ /**
2750
+ * Fetches the output content for a specific execution by its reference ID.
2751
+ *
2752
+ * Convenience method that retrieves the raw result and extracts just the output content.
2753
+ *
2754
+ * @param referenceId - The reference ID of the execution to retrieve.
2755
+ * @throws {Error} If no result found with the given reference ID.
2756
+ * @returns A promise resolving to the execution output content.
2757
+ *
2758
+ * @example
2759
+ * ```typescript
2760
+ * const output = await result.getResult('my-ref-id')
2761
+ * console.log('Output:', output)
2762
+ * ```
2763
+ */
2764
+ async getResult(referenceId) {
2765
+ const result = await this.getRawResult(referenceId);
2766
+ return result.outputContent.content;
2767
+ }
2768
+ /**
2769
+ * Validates that the output file is available for access.
2770
+ *
2771
+ * @throws {Error} If batch is not completed or output file is missing.
2772
+ * @private
2773
+ */
2774
+ validateOutputFile() {
2775
+ if (this._response.status !== "completed") {
2776
+ throw new Error("Batch execution is not completed");
2777
+ }
2778
+ if (!this._response.outputFile) {
2779
+ throw new Error("Output file not found");
2780
+ }
2781
+ }
2782
+ }
2783
+ class BatchExecution extends Emittery__default {
2784
+ /**
2785
+ * Creates a new batch execution instance.
2786
+ *
2787
+ * @param id - Unique identifier for this batch execution.
2788
+ * @param client - HTTP client for making API requests.
2789
+ * @param params - Batch execution parameters.
2790
+ * @param creationResponse - Initial response from batch creation.
2791
+ * @internal
2792
+ */
2793
+ constructor(id, client, params = {}, creationResponse) {
2794
+ super();
2795
+ __publicField$4(this, "_client");
2796
+ __publicField$4(this, "_id");
2797
+ __publicField$4(this, "_params");
2798
+ __publicField$4(this, "_abortController");
2799
+ __publicField$4(this, "_creationResponse");
2800
+ __publicField$4(this, "_status", "created");
2801
+ __publicField$4(this, "_resultPromise");
2802
+ this._id = id;
2803
+ this._client = client;
2804
+ this._params = params;
2805
+ this._abortController = new AbortController();
2806
+ this._creationResponse = creationResponse;
2807
+ }
2808
+ /**
2809
+ * Gets the latest known status of the batch execution.
2810
+ *
2811
+ * Status values and transitions:
2812
+ * - `created` → `validating` → `running` → `completed` or `failed`
2813
+ * - Can transition to `canceled` from any non-terminal state
2814
+ *
2815
+ * Use the `statusChange` event to track status transitions in real-time.
2816
+ *
2817
+ * @returns The current status of the batch execution.
2818
+ *
2819
+ * @example
2820
+ * ```typescript
2821
+ * const execution = await batch.execute()
2822
+ * console.log(execution.status) // 'created'
2823
+ *
2824
+ * execution.on('statusChange', ([status]) => {
2825
+ * console.log('New status:', status)
2826
+ * })
2827
+ *
2828
+ * await execution.result
2829
+ * console.log(execution.status) // 'completed' or 'failed'
2830
+ * ```
2831
+ */
2832
+ get status() {
2833
+ return this._status;
2834
+ }
2835
+ /**
2836
+ * Gets the unique identifier for this batch execution.
2837
+ *
2838
+ * @returns The batch execution ID.
2839
+ */
2840
+ get id() {
2841
+ return this._id;
2842
+ }
2843
+ /**
2844
+ * Gets the batch execution parameters.
2845
+ *
2846
+ * @returns The batch parameters.
2847
+ */
2848
+ get params() {
2849
+ return this._params;
2850
+ }
2851
+ /**
2852
+ * Cancels the batch execution.
2853
+ *
2854
+ * Sends a cancellation request to the server and aborts any ongoing polling.
2855
+ * The batch will stop processing, but already-completed executions remain available.
2856
+ *
2857
+ * @returns A promise that resolves when the cancellation request completes.
2858
+ *
2859
+ * @example
2860
+ * ```typescript
2861
+ * const execution = await batch.execute()
2862
+ * execution.poll()
2863
+ *
2864
+ * // Cancel after some condition
2865
+ * if (shouldCancel) {
2866
+ * await execution.cancel()
2867
+ * console.log(execution.status) // 'canceled'
2868
+ * }
2869
+ * ```
2870
+ */
2871
+ async cancel() {
2872
+ await this._client.put(`/_services/batch/batches/${this._id}/cancel`);
2873
+ this._status = "canceled";
2874
+ this._abortController.abort();
2875
+ }
2876
+ /**
2877
+ * Starts polling for the batch result without waiting for the promise to resolve.
2878
+ * This allows users to track batch progress via events rather than awaiting a promise.
2879
+ *
2880
+ * The following events will be emitted during polling:
2881
+ * - `statusChange`: Emitted when the batch status changes (e.g., 'created' → 'running' → 'completed')
2882
+ * - `poll`: Emitted on each polling attempt with the server response
2883
+ * - `success`: Emitted when the batch completes successfully with the final result
2884
+ * - `error`: Emitted if the batch fails
2885
+ *
2886
+ * **Important:** Events are only emitted while polling is active. You must call `poll()` or
2887
+ * await `execution.result` to start polling. Simply setting up event listeners without starting
2888
+ * polling will not trigger any events.
2889
+ *
2890
+ * @example
2891
+ * ```typescript
2892
+ * const execution = await batch.execute()
2893
+ *
2894
+ * // Set up event listeners
2895
+ * execution.on('statusChange', ([status, response]) => {
2896
+ * console.log(`Status: ${status}`)
2897
+ * if (response.state) {
2898
+ * const { completed, total } = response.state
2899
+ * console.log(`Progress: ${completed}/${total}`)
2900
+ * }
2901
+ * })
2902
+ *
2903
+ * execution.on('success', (result) => {
2904
+ * console.log('Batch completed!')
2905
+ * console.log('Request ID:', result.requestId)
2906
+ * })
2907
+ *
2908
+ * execution.on('error', (error) => {
2909
+ * console.error('Batch failed:', error)
2910
+ * })
2911
+ *
2912
+ * // Start polling without waiting
2913
+ * execution.poll()
2914
+ * ```
2915
+ */
2916
+ poll() {
2917
+ if (this._resultPromise) {
2918
+ return;
2919
+ }
2920
+ this._resultPromise = this.startPolling();
2921
+ this._resultPromise.catch(() => {
2922
+ });
2923
+ }
2924
+ /**
2925
+ * Sets the batch status and emits statusChange event if changed.
2926
+ *
2927
+ * @param status - The new status.
2928
+ * @param response - The response containing the status.
2929
+ * @private
2930
+ */
2931
+ setStatus(status, response) {
2932
+ const changed = this._status !== status;
2933
+ this._status = status;
2934
+ if (changed) {
2935
+ this.emit("statusChange", [status, response]);
2936
+ }
2937
+ }
2938
+ /**
2939
+ * Starts polling the server for batch completion.
2940
+ * Continues polling until the batch completes, fails, or times out.
2941
+ *
2942
+ * @throws {BatchExecutionFailedError} If the batch fails on the server.
2943
+ * @throws {Error} If the polling operation times out.
2944
+ * @returns A promise resolving to the final batch result.
2945
+ * @private
2946
+ */
2947
+ async startPolling() {
2948
+ this.emit("statusChange", [this._status, this._creationResponse]);
2949
+ return new Poller({
2950
+ interval: transformDurationToMs(this._params.pollingInterval) ?? 1e3,
2951
+ // 1 second
2952
+ timeout: transformDurationToMs(this._params.pollingTimeout) ?? 6e4,
2953
+ // 1 minute
2954
+ abortSignal: this._abortController.signal
2955
+ }).start(async () => {
2956
+ const response = await this._client.get(
2957
+ `/_services/batch/batches/${this._id}`,
2958
+ { signal: this._abortController.signal }
2959
+ );
2960
+ this.emit("poll", response);
2961
+ this.setStatus(response.status, response);
2962
+ if (response.status === "failed") {
2963
+ const error = new BatchExecutionFailedError(response);
2964
+ this._abortController.abort();
2965
+ this.emit("error", error);
2966
+ throw error;
2967
+ }
2968
+ if (response.status !== "completed") {
2969
+ return {
2970
+ done: false,
2971
+ value: void 0
2972
+ };
2973
+ }
2974
+ const result = new BatchExecutionResult(this._client, response);
2975
+ this.emit("success", result);
2976
+ return {
2977
+ done: true,
2978
+ value: result
2979
+ };
2980
+ });
2981
+ }
2982
+ /**
2983
+ * Gets the batch execution result. Automatically starts polling if not already started.
2984
+ *
2985
+ * @returns A promise resolving to the batch execution result.
2986
+ *
2987
+ * @example
2988
+ * ```typescript
2989
+ * const execution = await batch.execute()
2990
+ * const result = await execution.result
2991
+ *
2992
+ * // Access results
2993
+ * const outputs = await result.getResults()
2994
+ * console.log(`Got ${outputs.length} results`)
2995
+ * ```
2996
+ */
2997
+ get result() {
2998
+ if (!this._resultPromise) {
2999
+ this._resultPromise = this.startPolling();
3000
+ }
3001
+ return this._resultPromise;
3002
+ }
3003
+ }
3004
+ class Batch {
3005
+ /**
3006
+ * Creates a new batch builder.
3007
+ *
3008
+ * @param client - HTTP client for making API requests.
3009
+ * @param canvasIdentifier - Canvas identification (ID + version or application ID).
3010
+ * @param params - Optional batch execution parameters.
3011
+ * @internal
3012
+ */
3013
+ constructor(client, canvasIdentifier, params = {}) {
3014
+ __publicField$4(this, "_client");
3015
+ __publicField$4(this, "_canvasIdentifier");
3016
+ __publicField$4(this, "_items", []);
3017
+ __publicField$4(this, "_params");
3018
+ this._client = client;
3019
+ this._canvasIdentifier = canvasIdentifier;
3020
+ this._params = params;
3021
+ }
3022
+ /**
3023
+ * Gets the current list of items in this batch.
3024
+ *
3025
+ * @returns Array of batch items.
3026
+ */
3027
+ get items() {
3028
+ return this._items;
3029
+ }
3030
+ /**
3031
+ * Gets the batch execution parameters.
3032
+ *
3033
+ * @returns The batch parameters.
3034
+ */
3035
+ get params() {
3036
+ return this._params;
3037
+ }
3038
+ /**
3039
+ * Gets the canvas identifier in the format expected by the API.
3040
+ *
3041
+ * @returns Canvas identifier object.
3042
+ * @private
3043
+ */
3044
+ get canvasIdentifier() {
3045
+ return "applicationId" in this._canvasIdentifier ? { applicationId: this._canvasIdentifier.applicationId } : { versionId: this._canvasIdentifier.versionId, canvasID: this._canvasIdentifier.id };
3046
+ }
3047
+ /**
3048
+ * Adds one or more items to the batch.
3049
+ *
3050
+ * Items without a reference ID will have UUIDs generated automatically.
3051
+ * This method can be called multiple times to build up the batch incrementally.
3052
+ *
3053
+ * @param item - Single item or array of items to add to the batch.
3054
+ *
3055
+ * @example
3056
+ * ```typescript
3057
+ * // Add single item
3058
+ * batch.add({
3059
+ * referenceId: 'my-custom-id',
3060
+ * variables: { query: 'Hello' }
3061
+ * })
3062
+ *
3063
+ * // Add multiple items
3064
+ * batch.add([
3065
+ * { variables: { query: 'First' } },
3066
+ * { variables: { query: 'Second' } },
3067
+ * { variables: { query: 'Third' } }
3068
+ * ])
3069
+ *
3070
+ * console.log(`Batch has ${batch.items.length} items`)
3071
+ * ```
3072
+ */
3073
+ add(item) {
3074
+ const items = Array.isArray(item) ? item : [item];
3075
+ for (const item2 of items) {
3076
+ this._items.push({
3077
+ ...item2,
3078
+ referenceId: item2.referenceId ?? crypto.randomUUID()
3079
+ });
3080
+ }
3081
+ }
3082
+ /**
3083
+ * Executes the batch by uploading the input file and creating a batch execution on the server.
3084
+ *
3085
+ * Returns a promise-like object that allows flexible usage patterns:
3086
+ * - Await for execution object: `const exec = await batch.execute()`
3087
+ * - Direct result access: `const result = await batch.execute().result`
3088
+ *
3089
+ * The batch items are serialized to JSONL format, uploaded to vault storage,
3090
+ * and submitted to the batch API for processing.
3091
+ *
3092
+ * @returns A promise-like object with a `result` property for direct result access.
3093
+ *
3094
+ * @example
3095
+ * ```typescript
3096
+ * // Direct result access (recommended for simple cases)
3097
+ * const result = await batch.execute().result
3098
+ * const outputs = await result.getResults()
3099
+ *
3100
+ * // Get execution object for event monitoring
3101
+ * const execution = await batch.execute()
3102
+ *
3103
+ * execution.on('statusChange', ([status, response]) => {
3104
+ * console.log(`Status: ${status}`)
3105
+ * if (response.state) {
3106
+ * console.log(`Progress: ${response.state.completed}/${response.state.total}`)
3107
+ * }
3108
+ * })
3109
+ *
3110
+ * execution.on('success', (result) => {
3111
+ * console.log('Batch completed!', result.requestId)
3112
+ * })
3113
+ *
3114
+ * const result = await execution.result
3115
+ *
3116
+ * // Iterate through results
3117
+ * for await (const output of result.iterateResults()) {
3118
+ * console.log(output)
3119
+ * }
3120
+ * ```
3121
+ */
3122
+ execute() {
3123
+ const jsonLines = this._items.map((item) => ({
3124
+ ...this.canvasIdentifier,
3125
+ ...item
3126
+ })).map((item) => transformObjectFromCamelCaseToSnakeCase(item)).map((item) => JSON.stringify(item));
3127
+ const fileContent = new Blob([jsonLines.join("\n")], { type: "application/jsonl" });
3128
+ const file = TelaFile.create(fileContent);
3129
+ const client = this._client;
3130
+ const params = this._params;
3131
+ async function execute() {
3132
+ const { fileUrl } = await uploadFile(file, client);
3133
+ const body = {
3134
+ task: "async-completion",
3135
+ inputFile: fileUrl,
3136
+ webhookUrl: params.webhookUrl
3137
+ };
3138
+ return client.post("/_services/batch/batches", {
3139
+ body
3140
+ }).then((response) => new BatchExecution(response.id, client, params, response));
3141
+ }
3142
+ return {
3143
+ then(onfulfilled, onrejected) {
3144
+ return Promise.resolve(execute()).then((execution) => onfulfilled?.(execution) ?? execution).catch(onrejected);
3145
+ },
3146
+ get result() {
3147
+ return Promise.resolve(execute()).then((execution) => execution.result);
3148
+ }
3149
+ };
3150
+ }
3151
+ }
3152
+
3153
+ var __defProp$3 = Object.defineProperty;
3154
+ var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3155
+ var __publicField$3 = (obj, key, value) => {
3156
+ __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
3157
+ return value;
3158
+ };
3159
+ function fetchById(id, client) {
3160
+ return client.get(`/prompt/${id}/promoted-version`);
3161
+ }
3162
+ function fetchByVersionId(versionId, client) {
3163
+ return client.get(`/prompt-version/${versionId}`);
3164
+ }
3165
+ function fetchByApplicationId(applicationId, client) {
3166
+ return client.get(`/prompt-application/${applicationId}/targetPromptVersion`);
3167
+ }
3168
+ function fetchByAny({ id, versionId, applicationId, client }) {
3169
+ if (applicationId) {
3170
+ return fetchByApplicationId(applicationId, client);
3171
+ }
3172
+ if (versionId) {
3173
+ return fetchByVersionId(versionId, client);
3174
+ }
3175
+ if (id) {
3176
+ return fetchById(id, client);
2293
3177
  }
2294
3178
  throw new Error("Either id, versionId, or applicationId must be provided");
2295
3179
  }
2296
- function validateSchemas(input, output, promptVersion) {
2297
- const canvasIdentifier = `${promptVersion.title} (${promptVersion.promptId})`;
2298
- if (input instanceof z.z.ZodType) {
3180
+ class Canvas {
3181
+ /**
3182
+ * Creates a new instance of the Canvas class. Usage of this constructor is not recommended.
3183
+ * Use the `tela.getCanvas` method instead.
3184
+ *
3185
+ * @private
3186
+ */
3187
+ constructor({ id, applicationId, name, versionId, input, output, client, variables, isWorkflow }) {
3188
+ __publicField$3(this, "_id");
3189
+ __publicField$3(this, "_versionId");
3190
+ __publicField$3(this, "_applicationId");
3191
+ __publicField$3(this, "_name");
3192
+ __publicField$3(this, "_input");
3193
+ __publicField$3(this, "_output");
3194
+ __publicField$3(this, "_client");
3195
+ __publicField$3(this, "_variables");
3196
+ __publicField$3(this, "_isWorkflow");
3197
+ this._id = id;
3198
+ this._applicationId = applicationId;
3199
+ this._name = name;
3200
+ this._versionId = versionId;
3201
+ this._input = input && input(zod);
3202
+ this._output = output && output(zod);
3203
+ this._client = client;
3204
+ this._variables = variables;
3205
+ this._isWorkflow = isWorkflow;
3206
+ }
3207
+ /**
3208
+ * Gets a canvas by its ID.
3209
+ *
3210
+ * @param options - The options to use to get the canvas.
3211
+ * @param options.id - The ID of the canvas to get.
3212
+ * @param options.versionId - The version ID of the canvas to get.
3213
+ * @param options.applicationId - The application ID of the canvas to get.
3214
+ * @param options.client - The client to use to make the request.
3215
+ * @param options.input - The input schema of the canvas to get.
3216
+ * @param options.output - The output schema of the canvas to get.
3217
+ * @returns The canvas.
3218
+ */
3219
+ static async get(options) {
3220
+ const { id, versionId, applicationId, client, input, output, skipSchemaValidation = false } = options;
3221
+ const promptVersion = await fetchByAny({ id, versionId, applicationId, client });
3222
+ const inputSchema = input && input(zod);
3223
+ const outputSchema = output && output(zod);
3224
+ if (!skipSchemaValidation) {
3225
+ validateSchemas("Canvas", inputSchema, outputSchema, promptVersion);
3226
+ }
3227
+ return new Canvas({
3228
+ id: promptVersion.promptId,
3229
+ versionId: promptVersion.id,
3230
+ applicationId: applicationId ?? void 0,
3231
+ name: promptVersion.title,
3232
+ input,
3233
+ output,
3234
+ client,
3235
+ variables: promptVersion.variables,
3236
+ isWorkflow: promptVersion.isWorkflow
3237
+ });
3238
+ }
3239
+ /**
3240
+ * Gets the unique identifier of this canvas.
3241
+ *
3242
+ * @returns The canvas ID.
3243
+ */
3244
+ get id() {
3245
+ if (!this._id) {
3246
+ throw new Error("Canvas ID is not set");
3247
+ }
3248
+ return this._id;
3249
+ }
3250
+ /**
3251
+ * Gets the name of this canvas, if provided.
3252
+ *
3253
+ * @returns The canvas name or undefined.
3254
+ */
3255
+ get name() {
3256
+ if (!this._name) {
3257
+ throw new Error("Canvas name is not set");
3258
+ }
3259
+ return this._name;
3260
+ }
3261
+ /**
3262
+ * Gets the version identifier of this canvas, if specified.
3263
+ * When undefined, the latest promoted version is used.
3264
+ *
3265
+ * @returns The version ID or undefined.
3266
+ */
3267
+ get versionId() {
3268
+ if (!this._versionId) {
3269
+ throw new Error("Canvas version ID is not set");
3270
+ }
3271
+ return this._versionId;
3272
+ }
3273
+ get applicationId() {
3274
+ if (!this._applicationId) {
3275
+ throw new Error("Canvas application ID is not set");
3276
+ }
3277
+ return this._applicationId;
3278
+ }
3279
+ /**
3280
+ * Gets the variables of this canvas.
3281
+ *
3282
+ * @returns The variables of the canvas.
3283
+ */
3284
+ get variables() {
3285
+ return this._variables;
3286
+ }
3287
+ /**
3288
+ * Gets whether this canvas is a workflow.
3289
+ *
3290
+ * @returns True if the canvas is a workflow.
3291
+ */
3292
+ get isWorkflow() {
3293
+ return this._isWorkflow;
3294
+ }
3295
+ /**
3296
+ * Gets whether this canvas is a workstation.
3297
+ * This is true if an application ID is provided.
3298
+ *
3299
+ * @returns True if the canvas is a workstation.
3300
+ */
3301
+ get isWorkstation() {
3302
+ return Boolean(this._applicationId);
3303
+ }
3304
+ /**
3305
+ * Validates and parses input variables using the canvas input schema.
3306
+ *
3307
+ * @param variables - Raw input variables to validate.
3308
+ * @returns Parsed and validated variables.
3309
+ * @throws {ZodError} If validation fails when a Zod schema is configured.
3310
+ */
3311
+ parseVariables(variables) {
2299
3312
  try {
2300
- const inputSchema = z.z.toJSONSchema(input, { unrepresentable: "any" });
2301
- const mismatches = validateInputSchema(inputSchema, promptVersion.variables);
2302
- if (mismatches.length === 0) {
2303
- return;
2304
- }
2305
- console.warn(
2306
- `[Tela SDK - Canvas Input Validation] Input schema mismatches for canvas "${canvasIdentifier}":`
2307
- );
2308
- for (const mismatch of mismatches) {
2309
- console.warn(` - ${mismatch.path}: ${mismatch.issue}`);
3313
+ if (this._input instanceof z.z.ZodType) {
3314
+ return this._input.parse(variables);
2310
3315
  }
3316
+ return variables;
2311
3317
  } catch (error) {
2312
- console.warn(
2313
- `[Tela SDK - Canvas Input Validation] Failed to validate input schema for canvas "${canvasIdentifier}":`,
2314
- error
2315
- );
3318
+ if (!(error instanceof z.ZodError)) {
3319
+ throw error;
3320
+ }
3321
+ throw new Error(z.z.prettifyError(error));
2316
3322
  }
2317
3323
  }
2318
- if (output instanceof z.z.ZodType) {
2319
- try {
2320
- const outputSchema = z.z.toJSONSchema(output);
2321
- const serverOutput = promptVersion.configuration.structuredOutput;
2322
- if (!serverOutput.enabled) {
2323
- console.warn(
2324
- `[Tela SDK - Canvas Output Validation] Output schema provided for canvas "${canvasIdentifier}", but structured output is not enabled on the server. The schema may not be enforced.`
2325
- );
2326
- return;
3324
+ execute(variables, params) {
3325
+ const parsedInput = this.parseVariables(variables);
3326
+ const idObject = this._applicationId ? { applicationId: this._applicationId } : { versionId: this._versionId, canvasId: this._id };
3327
+ const fullParams = {
3328
+ ...params ?? { async: false },
3329
+ ...idObject
3330
+ };
3331
+ const execution = new CanvasExecution(parsedInput, fullParams, this._output, this._client, this.isWorkstation);
3332
+ return {
3333
+ then(onfulfilled, onrejected) {
3334
+ return Promise.resolve(execution.start()).then(() => onfulfilled?.(execution) ?? execution).catch(onrejected);
3335
+ },
3336
+ get result() {
3337
+ return Promise.resolve(execution.start()).then(() => execution.result);
3338
+ }
3339
+ };
3340
+ }
3341
+ /**
3342
+ * Fetches an existing async execution by its ID.
3343
+ *
3344
+ * This method retrieves the current state of an async execution that was previously
3345
+ * started on this canvas. Only async executions can be fetched, as they are the only
3346
+ * ones with persistent UUIDs on the server.
3347
+ *
3348
+ * @param id - The UUID of the async execution to fetch.
3349
+ * @param options - Optional configuration for polling behavior.
3350
+ * @param options.pollingInterval - Time in milliseconds between polling attempts (default: 1000).
3351
+ * @param options.pollingTimeout - Maximum time in milliseconds to wait for completion (default: 60000).
3352
+ * @throws {InvalidExecutionModeError} If the provided ID is not a valid UUID.
3353
+ * @returns A promise resolving to a CanvasExecution instance with the fetched state.
3354
+ *
3355
+ * @example
3356
+ * ```typescript
3357
+ * // Start an async execution
3358
+ * const execution = await canvas.execute({ query: 'test' }, { async: true })
3359
+ * const executionId = execution.id
3360
+ *
3361
+ * // Later, fetch the execution by ID
3362
+ * const fetched = await canvas.getExecution(executionId)
3363
+ * console.log(fetched.status) // 'running', 'succeeded', or 'failed'
3364
+ *
3365
+ * // Use poll() for event-driven progress tracking
3366
+ * fetched.on('statusChange', (status) => console.log('Status:', status))
3367
+ * fetched.poll()
3368
+ * ```
3369
+ */
3370
+ async getExecution(id, options) {
3371
+ return CanvasExecution.fetch(
3372
+ id,
3373
+ this._output,
3374
+ this._client,
3375
+ {
3376
+ ...options,
3377
+ isTask: this.isWorkstation
3378
+ }
3379
+ );
3380
+ }
3381
+ /**
3382
+ * Prepares to execute this canvas in batch.
3383
+ *
3384
+ * @param params - The parameters for the batch.
3385
+ * @param params.pollingInterval - The interval between polling attempts.
3386
+ * @param params.pollingTimeout - The timeout for the batch.
3387
+ * @param params.webhookUrl - The webhook URL for the batch.
3388
+ *
3389
+ * @example
3390
+ * ```typescript
3391
+ * const batch = canvas.createBatch({
3392
+ * pollingInterval: '1s',
3393
+ * pollingTimeout: '1m',
3394
+ * webhookUrl: 'https://example.com/webhook',
3395
+ * })
3396
+ *
3397
+ * batch.add({
3398
+ * referenceId: crypto.randomUUID(), // Optional
3399
+ * variables: { query: 'Hello' },
3400
+ * })
3401
+ *
3402
+ * const execution = await batch.execute()
3403
+ * const result = await execution.result
3404
+ * const resultFile = await execution.downloadOutputFile()
3405
+ * ```
3406
+ *
3407
+ * @returns The batch instance that can be used to manage the batch.
3408
+ */
3409
+ createBatch(params = {}) {
3410
+ const canvasIdentifier = this._applicationId ? { applicationId: this._applicationId } : { versionId: this._versionId, id: this._id };
3411
+ return new Batch(this._client, canvasIdentifier, params);
3412
+ }
3413
+ }
3414
+
3415
+ const TaskStatus = z.z.enum(["created", "failed", "running", "validating", "completed", "cancelled"]);
3416
+ const OutputContent = z.z.object({
3417
+ role: z.z.literal("assistant"),
3418
+ content: z.z.unknown(),
3419
+ toolCalls: z.z.array(z.z.any()),
3420
+ functionCall: z.z.any()
3421
+ });
3422
+ const RawInput = z.z.object({
3423
+ async: z.z.boolean(),
3424
+ stream: z.z.boolean(),
3425
+ variables: z.z.record(z.z.string(), z.z.unknown()),
3426
+ applicationId: z.z.string()
3427
+ });
3428
+ z.z.object({
3429
+ id: z.z.string(),
3430
+ reference: z.z.number(),
3431
+ name: z.z.string(),
3432
+ status: TaskStatus,
3433
+ rawInput: RawInput,
3434
+ inputContent: z.z.any(),
3435
+ outputContent: OutputContent,
3436
+ originalOutputContent: OutputContent,
3437
+ createdBy: z.z.string(),
3438
+ approvedBy: z.z.any(),
3439
+ approvedAt: z.z.any(),
3440
+ completionRunId: z.z.string(),
3441
+ workflowRunId: z.z.any(),
3442
+ promptVersionId: z.z.string(),
3443
+ promptApplicationId: z.z.string(),
3444
+ workspaceId: z.z.string(),
3445
+ metadata: z.z.any(),
3446
+ tags: z.z.array(z.z.string()),
3447
+ createdAt: z.z.string(),
3448
+ updatedAt: z.z.string(),
3449
+ deletedAt: z.z.any(),
3450
+ requestId: z.z.string()
3451
+ });
3452
+
3453
+ var __defProp$2 = Object.defineProperty;
3454
+ var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3455
+ var __publicField$2 = (obj, key, value) => {
3456
+ __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
3457
+ return value;
3458
+ };
3459
+ class Task extends Emittery__default {
3460
+ constructor(client, variables, task, requestId, outputSchema, skipResultValidation = false) {
3461
+ super();
3462
+ __publicField$2(this, "_variables");
3463
+ __publicField$2(this, "_task");
3464
+ __publicField$2(this, "_abortController", new AbortController());
3465
+ __publicField$2(this, "_client");
3466
+ __publicField$2(this, "_outputSchema");
3467
+ __publicField$2(this, "_skipResultValidation");
3468
+ __publicField$2(this, "_resultPromise");
3469
+ __publicField$2(this, "_status");
3470
+ __publicField$2(this, "_requestId");
3471
+ this._variables = variables;
3472
+ this._task = task;
3473
+ this._client = client;
3474
+ this._outputSchema = outputSchema;
3475
+ this._skipResultValidation = skipResultValidation;
3476
+ this._status = task.status;
3477
+ this._requestId = requestId;
3478
+ }
3479
+ /**
3480
+ * Gets the unique task ID assigned by the server.
3481
+ *
3482
+ * @returns The task ID.
3483
+ */
3484
+ get id() {
3485
+ if (!this._task.id) {
3486
+ throw new Error("Task ID is not available");
3487
+ }
3488
+ return this._task.id;
3489
+ }
3490
+ /**
3491
+ * Gets the request ID from the `x-request-id` header of the task creation request.
3492
+ *
3493
+ * This is the request ID from the initial POST /task request that created the task.
3494
+ * Each API request has its own unique request ID.
3495
+ *
3496
+ * For polling operations, different request IDs are available:
3497
+ * - `task.requestId` - ID from the task creation request
3498
+ * - `pollResult.requestId` - ID from each polling request (in poll events)
3499
+ * - `result.requestId` - ID from the final successful polling request (in success events)
3500
+ *
3501
+ * @returns A promise that resolves to the request ID from the task creation request.
3502
+ *
3503
+ * @example
3504
+ * ```typescript
3505
+ * const task = await workstation.createTask({ query: 'test' })
3506
+ * const requestId = await task.requestId
3507
+ * console.log('Request ID:', requestId)
3508
+ * ```
3509
+ */
3510
+ get requestId() {
3511
+ return this._requestId;
3512
+ }
3513
+ /**
3514
+ * Gets the latest known status of the task.
3515
+ *
3516
+ * Status values and transitions:
3517
+ * - `created` → `running` → `completed` or `failed`
3518
+ *
3519
+ * **Important:** Status is set to `completed` only after successful validation.
3520
+ * If validation fails, status will be `failed` even if the API request succeeded.
3521
+ *
3522
+ * Use the `statusChange` event to track status transitions in real-time.
3523
+ *
3524
+ * @returns The current status of the task.
3525
+ *
3526
+ * @example
3527
+ * ```typescript
3528
+ * const task = await workstation.createTask({ query: 'test' })
3529
+ * console.log(task.status) // 'created'
3530
+ *
3531
+ * await task.result
3532
+ * console.log(task.status) // 'completed' or 'failed'
3533
+ * ```
3534
+ */
3535
+ get status() {
3536
+ return this._status;
3537
+ }
3538
+ /**
3539
+ * Sets the status of the task and emits statusChange event.
3540
+ *
3541
+ * @param status - The new status of the task.
3542
+ * @private
3543
+ */
3544
+ set status(status) {
3545
+ const changed = this._status !== status;
3546
+ this._status = status;
3547
+ if (changed) {
3548
+ this.emit("statusChange", status);
3549
+ }
3550
+ }
3551
+ /**
3552
+ * Gets the input variables provided to this task.
3553
+ *
3554
+ * @returns The variables object.
3555
+ */
3556
+ get variables() {
3557
+ return this._variables;
3558
+ }
3559
+ /**
3560
+ * Gets the task label (alias for name).
3561
+ *
3562
+ * @returns The task name.
3563
+ */
3564
+ get label() {
3565
+ return this.name;
3566
+ }
3567
+ /**
3568
+ * Gets the task name.
3569
+ *
3570
+ * @returns The task name.
3571
+ */
3572
+ get name() {
3573
+ return this._task.name;
3574
+ }
3575
+ /**
3576
+ * Gets the task tags.
3577
+ *
3578
+ * @returns The task tags.
3579
+ */
3580
+ get tags() {
3581
+ return this._task.tags;
3582
+ }
3583
+ /**
3584
+ * Gets the raw task definition from the server.
3585
+ *
3586
+ * @returns The raw task definition.
3587
+ */
3588
+ get rawTask() {
3589
+ return this._task;
3590
+ }
3591
+ /**
3592
+ * Starts polling for the task result without waiting for the promise to resolve.
3593
+ * This allows users to track task progress via events rather than awaiting a promise.
3594
+ *
3595
+ * The following events will be emitted during polling:
3596
+ * - `statusChange`: Emitted when the task status changes (e.g., 'created' → 'running' → 'completed')
3597
+ * - `poll`: Emitted on each polling attempt with the server response
3598
+ * - `success`: Emitted when the task completes successfully with the final result
3599
+ * - `error`: Emitted if the task fails
3600
+ *
3601
+ * **Important:** Events are only emitted while polling is active. You must call `poll()` or
3602
+ * await `task.result` to start polling. Simply setting up event listeners without starting
3603
+ * polling will not trigger any events.
3604
+ *
3605
+ * @example
3606
+ * ```typescript
3607
+ * const task = await workstation.createTask({ query: 'test' })
3608
+ *
3609
+ * // Set up event listeners
3610
+ * task.on('statusChange', (status) => {
3611
+ * console.log('Status:', status)
3612
+ * })
3613
+ *
3614
+ * task.on('success', (result) => {
3615
+ * console.log('Completed:', result)
3616
+ * })
3617
+ *
3618
+ * task.on('error', (error) => {
3619
+ * console.error('Failed:', error)
3620
+ * })
3621
+ *
3622
+ * // Start polling without waiting
3623
+ * task.poll()
3624
+ * ```
3625
+ */
3626
+ poll() {
3627
+ if (this._resultPromise) {
3628
+ return;
3629
+ }
3630
+ this._resultPromise = this.startPolling();
3631
+ this._resultPromise.catch(() => {
3632
+ });
3633
+ }
3634
+ /**
3635
+ * Gets the task result. Automatically starts polling if not already started.
3636
+ *
3637
+ * @returns A promise that resolves to the validated task output.
3638
+ *
3639
+ * @example
3640
+ * ```typescript
3641
+ * const task = await workstation.createTask({ query: 'test' })
3642
+ * const result = await task.result
3643
+ * console.log(result)
3644
+ * ```
3645
+ */
3646
+ get result() {
3647
+ if (this._resultPromise) {
3648
+ return this._resultPromise;
3649
+ }
3650
+ this._resultPromise = this.startPolling();
3651
+ return this._resultPromise;
3652
+ }
3653
+ /**
3654
+ * Starts the polling process to retrieve task results.
3655
+ * Emits events during the polling lifecycle and validates output before resolving.
3656
+ *
3657
+ * @returns A promise that resolves to the validated task output.
3658
+ * @private
3659
+ */
3660
+ async startPolling() {
3661
+ const result = await new Poller({
3662
+ interval: 1e3,
3663
+ timeout: 6e4,
3664
+ abortSignal: this._abortController.signal
3665
+ }).start(async () => {
3666
+ const response = await this._client.get(`/task/${this.id}`, {
3667
+ signal: this._abortController.signal
3668
+ });
3669
+ const newStatus = response.status;
3670
+ this.status = newStatus;
3671
+ this.emit("poll", response);
3672
+ if (response.status === "failed") {
3673
+ const error = new TaskFailedError(response, "Task failure reported by the server");
3674
+ this.status = "failed";
3675
+ this.emit("error", error);
3676
+ if (this.listenerCount("error") === 0) {
3677
+ throw error;
3678
+ }
3679
+ return {
3680
+ done: true,
3681
+ value: void 0
3682
+ };
2327
3683
  }
2328
- const mismatches = validateOutputSchema(outputSchema, serverOutput.schema);
2329
- if (mismatches.length === 0) {
2330
- return;
3684
+ if (!["completed", "validating"].includes(response.status)) {
3685
+ return {
3686
+ done: false,
3687
+ value: void 0
3688
+ };
2331
3689
  }
2332
- console.warn(
2333
- `[Tela SDK - Canvas Output Validation] Output schema mismatches for canvas "${canvasIdentifier}":`
2334
- );
2335
- for (const mismatch of mismatches) {
2336
- console.warn(` - ${mismatch.path}: ${mismatch.issue}`);
3690
+ return {
3691
+ done: true,
3692
+ value: response
3693
+ };
3694
+ });
3695
+ try {
3696
+ const value = result;
3697
+ if (value === void 0) {
3698
+ return void 0;
2337
3699
  }
3700
+ const content = value.outputContent.content;
3701
+ const validatedContent = this._skipResultValidation || !(this._outputSchema instanceof z__default.ZodType) ? content : this._outputSchema.parse(content);
3702
+ this.status = value.status;
3703
+ this.emit("success", validatedContent);
3704
+ return validatedContent;
2338
3705
  } catch (error) {
2339
- console.warn(
2340
- `[Tela SDK - Canvas Output Validation] Failed to validate output schema for canvas "${canvasIdentifier}":`,
2341
- error
2342
- );
3706
+ this.status = "failed";
3707
+ const castError = error instanceof Error ? error : new Error(String(error));
3708
+ const message = castError instanceof z.ZodError ? z__default.prettifyError(castError) : castError.message;
3709
+ this.emit("error", new TaskFailedError(result, message, castError));
3710
+ if (this.listenerCount("error") === 0) {
3711
+ throw error;
3712
+ }
3713
+ return void 0;
2343
3714
  }
2344
3715
  }
2345
3716
  }
2346
- class Canvas {
3717
+
3718
+ var __defProp$1 = Object.defineProperty;
3719
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3720
+ var __publicField$1 = (obj, key, value) => {
3721
+ __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
3722
+ return value;
3723
+ };
3724
+ const DateRange = z__default.object({
3725
+ since: z__default.union([z__default.date().transform((date) => date.toISOString()), z__default.iso.datetime()]),
3726
+ until: z__default.union([z__default.date().transform((date) => date.toISOString()), z__default.iso.datetime()])
3727
+ });
3728
+ const TaskListFilters = z__default.looseObject({
3729
+ id: z__default.uuid().array().optional(),
3730
+ name: z__default.string().optional(),
3731
+ status: z__default.array(TaskStatus).optional(),
3732
+ approvedAt: DateRange.partial().optional(),
3733
+ createdAt: DateRange.partial().optional(),
3734
+ updatedAt: DateRange.partial().optional(),
3735
+ approvedBy: z__default.string().optional(),
3736
+ createdBy: z__default.string().optional(),
3737
+ completionRunId: z__default.uuid().optional(),
3738
+ promptVersionId: z__default.uuid().optional()
3739
+ }).transform(({ name, approvedAt, createdAt, updatedAt, ...rest }) => ({
3740
+ taskName: name,
3741
+ ...approvedAt ? { approvedAtSince: approvedAt.since, approvedAtUntil: approvedAt.until } : {},
3742
+ ...createdAt ? { createdAtSince: createdAt.since, createdAtUntil: createdAt.until } : {},
3743
+ ...updatedAt ? { updatedAtSince: updatedAt.since, updatedAtUntil: updatedAt.until } : {},
3744
+ ...rest
3745
+ }));
3746
+ const TaskListOptions = z__default.looseObject({
3747
+ limit: z__default.number().optional(),
3748
+ offset: z__default.number().optional(),
3749
+ order: z__default.object({
3750
+ by: z__default.enum(["createdAt", "updatedAt", "approvedAt", "status", "reference", "name"]),
3751
+ direction: z__default.enum(["asc", "desc"])
3752
+ }).optional()
3753
+ }).transform(({ order, ...rest }) => ({
3754
+ orderBy: order?.by,
3755
+ orderDirection: order?.direction,
3756
+ ...rest
3757
+ }));
3758
+ class Workstation {
2347
3759
  /**
2348
- * Creates a new instance of the Canvas class. Usage of this constructor is not recommended.
2349
- * Use the `tela.getCanvas` method instead.
3760
+ * Creates a new Workstation instance.
2350
3761
  *
2351
- * @private
3762
+ * Use {@link Workstation.get} instead.
3763
+ * @internal
2352
3764
  */
2353
- constructor({ id, applicationId, name, versionId, input, output, client, variables, isWorkflow }) {
3765
+ constructor({ client, applicationId, promptVersion, input, output }) {
2354
3766
  __publicField$1(this, "_id");
2355
- __publicField$1(this, "_versionId");
2356
- __publicField$1(this, "_applicationId");
2357
- __publicField$1(this, "_name");
3767
+ __publicField$1(this, "_promptVersion");
3768
+ __publicField$1(this, "_client");
2358
3769
  __publicField$1(this, "_input");
2359
3770
  __publicField$1(this, "_output");
2360
- __publicField$1(this, "_client");
2361
- __publicField$1(this, "_variables");
2362
- __publicField$1(this, "_isWorkflow");
2363
- this._id = id;
2364
- this._applicationId = applicationId;
2365
- this._name = name;
2366
- this._versionId = versionId;
3771
+ this._id = applicationId;
3772
+ this._promptVersion = promptVersion;
3773
+ this._client = client;
2367
3774
  this._input = input && input(zod);
2368
3775
  this._output = output && output(zod);
2369
- this._client = client;
2370
- this._variables = variables;
2371
- this._isWorkflow = isWorkflow;
2372
3776
  }
2373
3777
  /**
2374
- * Gets a canvas by its ID.
3778
+ * The unique identifier for this workstation (application ID).
3779
+ */
3780
+ get id() {
3781
+ return this._id;
3782
+ }
3783
+ /**
3784
+ * The prompt version configuration for this workstation.
3785
+ */
3786
+ get promptVersion() {
3787
+ return this._promptVersion;
3788
+ }
3789
+ /**
3790
+ * Retrieves a workstation by application ID and optionally validates schemas.
2375
3791
  *
2376
- * @param options - The options to use to get the canvas.
2377
- * @param options.id - The ID of the canvas to get.
2378
- * @param options.versionId - The version ID of the canvas to get.
2379
- * @param options.applicationId - The application ID of the canvas to get.
2380
- * @param options.client - The client to use to make the request.
2381
- * @param options.input - The input schema of the canvas to get.
2382
- * @param options.output - The output schema of the canvas to get.
2383
- * @returns The canvas.
3792
+ * This is the recommended way to create a Workstation instance.
3793
+ *
3794
+ * @param options - Configuration options
3795
+ * @param options.client - The BaseClient instance for API communication
3796
+ * @param options.applicationId - The unique ID of the workstation
3797
+ * @param options.input - Optional input schema function
3798
+ * @param options.output - Optional output schema function
3799
+ * @param options.skipSchemaValidation - Whether to skip schema validation (defaults to false)
3800
+ * @returns A promise that resolves to a Workstation instance
3801
+ *
3802
+ * @throws {Error} If schema validation fails (when schemas are provided and skipSchemaValidation is false)
3803
+ *
3804
+ * @example
3805
+ * ```typescript
3806
+ * const workstation = await Workstation.get({
3807
+ * client,
3808
+ * applicationId: 'app-123',
3809
+ * input: schema => schema.object({
3810
+ * query: schema.string(),
3811
+ * }),
3812
+ * output: schema => schema.object({
3813
+ * answer: schema.string(),
3814
+ * }),
3815
+ * })
3816
+ * ```
2384
3817
  */
2385
3818
  static async get(options) {
2386
- const { id, versionId, applicationId, client, input, output, skipSchemaValidation = false } = options;
2387
- const promptVersion = await fetchByAny({ id, versionId, applicationId, client });
3819
+ const { client, applicationId, input, output, skipSchemaValidation = false } = options;
3820
+ const id = z__default.uuid({ error: (error) => `Invalid application ID: '${error.input}'. Must be a valid UUID.` }).parse(applicationId);
3821
+ const promptVersion = await client.get(`/prompt-application/${id}/targetPromptVersion`);
2388
3822
  const inputSchema = input && input(zod);
2389
3823
  const outputSchema = output && output(zod);
2390
3824
  if (!skipSchemaValidation) {
2391
- validateSchemas(inputSchema, outputSchema, promptVersion);
3825
+ validateSchemas("Workstation", inputSchema, outputSchema, promptVersion);
2392
3826
  }
2393
- return new Canvas({
2394
- id: promptVersion.promptId,
2395
- versionId: promptVersion.id,
2396
- applicationId: applicationId ?? void 0,
2397
- name: promptVersion.title,
2398
- input,
2399
- output,
3827
+ return new Workstation({
2400
3828
  client,
2401
- variables: promptVersion.variables,
2402
- isWorkflow: promptVersion.isWorkflow
3829
+ applicationId: id,
3830
+ promptVersion,
3831
+ input,
3832
+ output
2403
3833
  });
2404
3834
  }
2405
3835
  /**
2406
- * Gets the unique identifier of this canvas.
3836
+ * Creates a new task for this workstation and returns a promise-like object.
2407
3837
  *
2408
- * @returns The canvas ID.
2409
- */
2410
- get id() {
2411
- if (!this._id) {
2412
- throw new Error("Canvas ID is not set");
2413
- }
2414
- return this._id;
2415
- }
2416
- /**
2417
- * Gets the name of this canvas, if provided.
3838
+ * The returned object can be awaited directly to get the Task instance, or you can
3839
+ * access `.result` to get the final task output directly.
2418
3840
  *
2419
- * @returns The canvas name or undefined.
2420
- */
2421
- get name() {
2422
- if (!this._name) {
2423
- throw new Error("Canvas name is not set");
2424
- }
2425
- return this._name;
2426
- }
2427
- /**
2428
- * Gets the version identifier of this canvas, if specified.
2429
- * When undefined, the latest promoted version is used.
3841
+ * @param variables - Input variables for the task (must match the input schema)
3842
+ * @param params - Optional task parameters (label, tags, skipResultValidation)
3843
+ * @returns A promise-like object that resolves to the Task instance
2430
3844
  *
2431
- * @returns The version ID or undefined.
2432
- */
2433
- get versionId() {
2434
- if (!this._versionId) {
2435
- throw new Error("Canvas version ID is not set");
2436
- }
2437
- return this._versionId;
2438
- }
2439
- get applicationId() {
2440
- if (!this._applicationId) {
2441
- throw new Error("Canvas application ID is not set");
2442
- }
2443
- return this._applicationId;
2444
- }
2445
- /**
2446
- * Gets the variables of this canvas.
3845
+ * @example
3846
+ * ```typescript
3847
+ * // Get the task instance
3848
+ * const task = await workstation.createTask({ query: 'test' })
2447
3849
  *
2448
- * @returns The variables of the canvas.
3850
+ * // Or get the result directly
3851
+ * const result = await workstation.createTask({ query: 'test' }).result
3852
+ * ```
2449
3853
  */
2450
- get variables() {
2451
- return this._variables;
3854
+ createTask(variables, params = {}) {
3855
+ const validatedVariables = this.parseVariables(variables);
3856
+ const taskDefinitionPromise = this.resolveVariables(validatedVariables).then((resolvedVariables) => this._client.post(`/task`, {
3857
+ body: {
3858
+ name: params.label ?? "Task from SDK",
3859
+ tags: params.tags ?? void 0,
3860
+ promptApplicationId: this._id,
3861
+ rawInput: {
3862
+ variables: resolvedVariables
3863
+ }
3864
+ },
3865
+ transformCase: false
3866
+ })).then((response) => {
3867
+ return new Task(
3868
+ this._client,
3869
+ variables,
3870
+ response[0],
3871
+ response.requestId,
3872
+ this._output,
3873
+ params.skipResultValidation ?? false
3874
+ );
3875
+ });
3876
+ return {
3877
+ then(onfulfilled, onrejected) {
3878
+ return Promise.resolve(taskDefinitionPromise).then((task) => onfulfilled?.(task) ?? task).catch(onrejected);
3879
+ },
3880
+ get result() {
3881
+ return Promise.resolve(taskDefinitionPromise).then((task) => task.result);
3882
+ }
3883
+ };
2452
3884
  }
2453
3885
  /**
2454
- * Gets whether this canvas is a workflow.
3886
+ * Retrieves an existing task by its ID.
2455
3887
  *
2456
- * @returns True if the canvas is a workflow.
2457
- */
2458
- get isWorkflow() {
2459
- return this._isWorkflow;
2460
- }
2461
- /**
2462
- * Gets whether this canvas is a workstation.
2463
- * This is true if an application ID is provided.
3888
+ * This is useful for resuming monitoring of a task that was created earlier.
2464
3889
  *
2465
- * @returns True if the canvas is a workstation.
3890
+ * @param id - The task ID to retrieve
3891
+ * @param options - Optional configuration
3892
+ * @param options.skipResultValidation - Whether to skip output validation
3893
+ * @returns A promise that resolves to the Task instance
3894
+ *
3895
+ * @example
3896
+ * ```typescript
3897
+ * const task = await workstation.getTask('task-id')
3898
+ *
3899
+ * // Set up event listeners
3900
+ * task.on('statusChange', (status) => console.log('Status:', status))
3901
+ * task.on('success', (result) => console.log('Result:', result))
3902
+ *
3903
+ * // Start polling
3904
+ * task.poll()
3905
+ * ```
2466
3906
  */
2467
- get isWorkstation() {
2468
- return Boolean(this._applicationId);
3907
+ async getTask(id, options = {}) {
3908
+ const taskResponse = await this._client.get(`/task/${id}`);
3909
+ return new Task(
3910
+ this._client,
3911
+ taskResponse.rawInput.variables,
3912
+ taskResponse,
3913
+ taskResponse.requestId,
3914
+ this._output,
3915
+ options.skipResultValidation ?? false
3916
+ );
2469
3917
  }
2470
3918
  /**
2471
- * Validates and parses input variables using the canvas input schema.
3919
+ * Validates and parses input variables using the workstation input schema.
2472
3920
  *
2473
3921
  * @param variables - Raw input variables to validate.
2474
3922
  * @returns Parsed and validated variables.
@@ -2476,7 +3924,7 @@ class Canvas {
2476
3924
  */
2477
3925
  parseVariables(variables) {
2478
3926
  try {
2479
- if (this._input instanceof z.z.ZodType) {
3927
+ if (this._input instanceof z__default.ZodType) {
2480
3928
  return this._input.parse(variables);
2481
3929
  }
2482
3930
  return variables;
@@ -2484,65 +3932,140 @@ class Canvas {
2484
3932
  if (!(error instanceof z.ZodError)) {
2485
3933
  throw error;
2486
3934
  }
2487
- throw new Error(z.z.prettifyError(error));
3935
+ throw new Error(z__default.prettifyError(error));
2488
3936
  }
2489
3937
  }
2490
- execute(variables, params) {
2491
- const parsedInput = this.parseVariables(variables);
2492
- const idObject = this._applicationId ? { applicationId: this._applicationId } : { versionId: this._versionId, canvasId: this._id };
2493
- const fullParams = {
2494
- ...params ?? { async: false },
2495
- ...idObject
2496
- };
2497
- const execution = new CanvasExecution(parsedInput, fullParams, this._output, this._client, this.isWorkstation);
2498
- return {
2499
- then(onfulfilled, onrejected) {
2500
- return Promise.resolve(execution.start()).then(() => onfulfilled?.(execution) ?? execution).catch(onrejected);
2501
- },
2502
- get result() {
2503
- return Promise.resolve(execution.start()).then(() => execution.result);
3938
+ /**
3939
+ * Processes variables and uploads any TelaFile instances to the server.
3940
+ * Replaces TelaFile objects with their uploaded URLs while preserving other values.
3941
+ *
3942
+ * @returns A promise resolving to the processed variables object.
3943
+ */
3944
+ async resolveVariables(inputVariables) {
3945
+ const variables = {};
3946
+ for (const [key, value] of Object.entries(inputVariables)) {
3947
+ if (isTelaFileArray(value)) {
3948
+ variables[key] = { files: await uploadFiles(value, this._client) };
3949
+ continue;
2504
3950
  }
2505
- };
3951
+ if (isTelaFile(value)) {
3952
+ variables[key] = await uploadFile(value, this._client);
3953
+ continue;
3954
+ }
3955
+ variables[key] = value;
3956
+ }
3957
+ return variables;
2506
3958
  }
2507
3959
  /**
2508
- * Fetches an existing async execution by its ID.
3960
+ * Lists tasks for this workstation with optional filtering and pagination.
2509
3961
  *
2510
- * This method retrieves the current state of an async execution that was previously
2511
- * started on this canvas. Only async executions can be fetched, as they are the only
2512
- * ones with persistent UUIDs on the server.
3962
+ * Returns a page of tasks matching the specified filters, along with metadata
3963
+ * for pagination.
2513
3964
  *
2514
- * @param id - The UUID of the async execution to fetch.
2515
- * @param options - Optional configuration for polling behavior.
2516
- * @param options.pollingInterval - Time in milliseconds between polling attempts (default: 1000).
2517
- * @param options.pollingTimeout - Maximum time in milliseconds to wait for completion (default: 60000).
2518
- * @throws {InvalidExecutionModeError} If the provided ID is not a valid UUID.
2519
- * @returns A promise resolving to a CanvasExecution instance with the fetched state.
3965
+ * @param params - Query parameters
3966
+ * @param params.filters - Optional filters to apply (ID, name, status, dates, etc.)
3967
+ * @param params.options - Optional pagination and sorting options
3968
+ * @param params.rawQuery - Raw query object (internal use, overrides filters/options)
3969
+ * @returns A promise that resolves to an object containing tasks and pagination metadata
2520
3970
  *
2521
3971
  * @example
2522
3972
  * ```typescript
2523
- * // Start an async execution
2524
- * const execution = await canvas.execute({ query: 'test' }, { async: true })
2525
- * const executionId = execution.id
2526
- *
2527
- * // Later, fetch the execution by ID
2528
- * const fetched = await canvas.getExecution(executionId)
2529
- * console.log(fetched.status) // 'running', 'succeeded', or 'failed'
3973
+ * // Get first 10 completed tasks
3974
+ * const { tasks, meta } = await workstation.listTasks({
3975
+ * filters: { status: ['completed'] },
3976
+ * options: { limit: 10, offset: 0 },
3977
+ * })
2530
3978
  *
2531
- * // Use poll() for event-driven progress tracking
2532
- * fetched.on('statusChange', (status) => console.log('Status:', status))
2533
- * fetched.poll()
3979
+ * // Sort by creation date
3980
+ * const { tasks, meta } = await workstation.listTasks({
3981
+ * options: {
3982
+ * order: { by: 'createdAt', direction: 'desc' },
3983
+ * limit: 20,
3984
+ * },
3985
+ * })
2534
3986
  * ```
2535
3987
  */
2536
- async getExecution(id, options) {
2537
- return CanvasExecution.fetch(
2538
- id,
2539
- this._output,
3988
+ async listTasks({ filters, options, rawQuery }) {
3989
+ function getQuery(id) {
3990
+ if (rawQuery) {
3991
+ return rawQuery;
3992
+ }
3993
+ const validatedFilters = TaskListFilters.optional().parse(filters);
3994
+ const validatedOptions = TaskListOptions.optional().parse(options);
3995
+ return {
3996
+ promptApplicationId: id,
3997
+ objectLinks: true,
3998
+ ...validatedFilters,
3999
+ ...validatedOptions
4000
+ };
4001
+ }
4002
+ const query = getQuery(this._id);
4003
+ const response = await this._client.get(`/task`, {
4004
+ query,
4005
+ transformCase: false
4006
+ });
4007
+ const tasks = response.data.map((task) => new Task(
2540
4008
  this._client,
2541
- {
2542
- ...options,
2543
- isTask: this.isWorkstation
4009
+ task.rawInput?.variables,
4010
+ task,
4011
+ task.requestId,
4012
+ this._output
4013
+ ));
4014
+ return {
4015
+ tasks,
4016
+ meta: response.meta
4017
+ };
4018
+ }
4019
+ /**
4020
+ * Asynchronously iterates through all tasks matching the specified filters.
4021
+ *
4022
+ * This generator automatically handles pagination, fetching additional pages
4023
+ * as needed. Each iteration yields a task and the current page metadata.
4024
+ *
4025
+ * @param params - Query parameters
4026
+ * @param params.filters - Optional filters to apply (ID, name, status, dates, etc.)
4027
+ * @param params.options - Optional initial pagination and sorting options
4028
+ * @yields A tuple of [task, metadata] for each task
4029
+ *
4030
+ * @example
4031
+ * ```typescript
4032
+ * // Iterate through all pending tasks
4033
+ * for await (const [task, meta] of workstation.iterateTasks({
4034
+ * filters: { status: ['pending'] },
4035
+ * })) {
4036
+ * console.log(`Task ${task.id}: ${task.status}`)
4037
+ * console.log(`Page ${meta.currentPage} of ${meta.totalPages}`)
4038
+ * }
4039
+ *
4040
+ * // Process tasks in batches
4041
+ * for await (const [task, meta] of workstation.iterateTasks({
4042
+ * options: { limit: 50 },
4043
+ * })) {
4044
+ * await processTask(task)
4045
+ * }
4046
+ * ```
4047
+ */
4048
+ async *iterateTasks({ filters, options }) {
4049
+ let rawQuery;
4050
+ let hasMore = true;
4051
+ while (hasMore) {
4052
+ const { tasks, meta } = await this.listTasks({
4053
+ filters,
4054
+ options,
4055
+ rawQuery
4056
+ });
4057
+ for (const task of tasks) {
4058
+ yield [task, meta];
2544
4059
  }
2545
- );
4060
+ if (meta.links.next !== null) {
4061
+ rawQuery = {
4062
+ ...meta.links.next,
4063
+ objectLinks: true
4064
+ };
4065
+ } else {
4066
+ hasMore = false;
4067
+ }
4068
+ }
2546
4069
  }
2547
4070
  }
2548
4071
 
@@ -2607,6 +4130,17 @@ const _TelaSDK = class _TelaSDK extends BaseClient {
2607
4130
  });
2608
4131
  }
2609
4132
  });
4133
+ __publicField(this, "workstation", {
4134
+ get: async (options) => {
4135
+ return Workstation.get({
4136
+ applicationId: options.applicationId,
4137
+ input: options.input,
4138
+ output: options.output,
4139
+ skipSchemaValidation: options.skipSchemaValidation,
4140
+ client: this
4141
+ });
4142
+ }
4143
+ });
2610
4144
  this.opts = { baseURL, ...rest };
2611
4145
  this.apiKey = apiKey;
2612
4146
  this.jwt = jwt;
@@ -2666,6 +4200,10 @@ __publicField(_TelaSDK, "FileUploadError", FileUploadError);
2666
4200
  __publicField(_TelaSDK, "MissingApiKeyOrJWTError", MissingApiKeyOrJWTError);
2667
4201
  /** Thrown when both an API key and a JWT are provided. */
2668
4202
  __publicField(_TelaSDK, "ConflictApiKeyAndJWTError", ConflictApiKeyAndJWTError);
4203
+ /** Thrown when a canvas execution fails on the server. */
4204
+ __publicField(_TelaSDK, "ExecutionFailedError", ExecutionFailedError);
4205
+ /** Thrown when a workstation task fails on the server. */
4206
+ __publicField(_TelaSDK, "TaskFailedError", TaskFailedError);
2669
4207
  let TelaSDK = _TelaSDK;
2670
4208
  function createTelaClient(opts) {
2671
4209
  return new TelaSDK(opts);
@@ -2676,6 +4214,7 @@ exports.AuthenticationError = AuthenticationError;
2676
4214
  exports.AuthorizationError = AuthorizationError;
2677
4215
  exports.BadRequestError = BadRequestError;
2678
4216
  exports.BaseClient = BaseClient;
4217
+ exports.BatchExecutionFailedError = BatchExecutionFailedError;
2679
4218
  exports.ConflictApiKeyAndJWTError = ConflictApiKeyAndJWTError;
2680
4219
  exports.ConflictError = ConflictError;
2681
4220
  exports.ConnectionError = ConnectionError;
@@ -2690,6 +4229,7 @@ exports.InvalidFileURL = InvalidFileURL;
2690
4229
  exports.MissingApiKeyOrJWTError = MissingApiKeyOrJWTError;
2691
4230
  exports.NotFoundError = NotFoundError;
2692
4231
  exports.RateLimitError = RateLimitError;
4232
+ exports.TaskFailedError = TaskFailedError;
2693
4233
  exports.TelaError = TelaError;
2694
4234
  exports.TelaFile = TelaFile;
2695
4235
  exports.TelaFileSchema = TelaFileSchema;
@@ -2697,4 +4237,6 @@ exports.TelaSDK = TelaSDK;
2697
4237
  exports.UnprocessableEntityError = UnprocessableEntityError;
2698
4238
  exports.UserAbortError = UserAbortError;
2699
4239
  exports.createTelaClient = createTelaClient;
4240
+ exports.isTelaFile = isTelaFile;
4241
+ exports.isTelaFileArray = isTelaFileArray;
2700
4242
  exports.toError = toError;