@workglow/ai 0.2.8 → 0.2.9

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/browser.js CHANGED
@@ -321,6 +321,7 @@ class QueuedExecutionStrategy {
321
321
  concurrency;
322
322
  autoCreate;
323
323
  initPromise = null;
324
+ limiter;
324
325
  constructor(queueName, concurrency = 1, autoCreate = true) {
325
326
  this.queueName = queueName;
326
327
  this.concurrency = concurrency;
@@ -358,8 +359,42 @@ class QueuedExecutionStrategy {
358
359
  }
359
360
  abort() {}
360
361
  async* executeStream(jobInput, context, runnerId) {
361
- const result = await this.execute(jobInput, context, runnerId);
362
- yield { type: "finish", data: result };
362
+ if (context.signal.aborted) {
363
+ throw context.signal.reason ?? new AbortSignalJobError2("The operation was aborted");
364
+ }
365
+ await this.ensureQueue();
366
+ const limiter = this.limiter;
367
+ if (!limiter) {
368
+ throw new TaskConfigurationError(`QueuedExecutionStrategy: limiter was not initialized for queue "${this.queueName}"`);
369
+ }
370
+ await this.acquireLimiterSlot(limiter, context.signal);
371
+ try {
372
+ const job = new AiJob({
373
+ queueName: jobInput.aiProvider,
374
+ jobRunId: runnerId,
375
+ input: jobInput
376
+ });
377
+ yield* job.executeStream(jobInput, {
378
+ signal: context.signal,
379
+ updateProgress: context.updateProgress
380
+ });
381
+ } finally {
382
+ await limiter.recordJobCompletion();
383
+ }
384
+ }
385
+ async acquireLimiterSlot(limiter, signal) {
386
+ const poll = async () => {
387
+ while (!await limiter.canProceed()) {
388
+ if (signal.aborted) {
389
+ throw signal.reason ?? new AbortSignalJobError2("The operation was aborted");
390
+ }
391
+ const next = await limiter.getNextAvailableTime();
392
+ const delay = Math.max(0, next.getTime() - Date.now());
393
+ await new Promise((resolve) => setTimeout(resolve, Math.min(delay, 50)));
394
+ }
395
+ };
396
+ await poll();
397
+ await limiter.recordJobStart();
363
398
  }
364
399
  ensureQueue() {
365
400
  if (!this.initPromise) {
@@ -377,6 +412,7 @@ class QueuedExecutionStrategy {
377
412
  if (!existing.server.isRunning()) {
378
413
  await existing.server.start();
379
414
  }
415
+ this.limiter = existing.server.limiter;
380
416
  return existing;
381
417
  }
382
418
  if (!this.autoCreate) {
@@ -384,10 +420,11 @@ class QueuedExecutionStrategy {
384
420
  }
385
421
  const storage = new InMemoryQueueStorage(this.queueName);
386
422
  await storage.setupDatabase();
423
+ this.limiter = new ConcurrencyLimiter(this.concurrency);
387
424
  const server = new JobQueueServer(AiJob, {
388
425
  storage,
389
426
  queueName: this.queueName,
390
- limiter: new ConcurrencyLimiter(this.concurrency)
427
+ limiter: this.limiter
391
428
  });
392
429
  const client = new JobQueueClient({
393
430
  storage,
@@ -411,6 +448,7 @@ class QueuedExecutionStrategy {
411
448
  if (!raced.server.isRunning()) {
412
449
  await raced.server.start();
413
450
  }
451
+ this.limiter = raced.server.limiter;
414
452
  return raced;
415
453
  }
416
454
  }
@@ -799,8 +837,8 @@ class QueuedAiProvider extends AiProvider {
799
837
  // src/task/index.ts
800
838
  import { TaskRegistry } from "@workglow/task-graph";
801
839
 
802
- // src/task/BackgroundRemovalTask.ts
803
- import { CreateWorkflow, Workflow } from "@workglow/task-graph";
840
+ // src/task/AiChatTask.ts
841
+ import { TaskConfigSchema as TaskConfigSchema2 } from "@workglow/task-graph";
804
842
 
805
843
  // src/task/base/AiTaskSchemas.ts
806
844
  var TypeLanguage = (annotations = {}) => ({
@@ -959,8 +997,8 @@ var TypeCategory = {
959
997
  description: "Classification category with label and score"
960
998
  };
961
999
 
962
- // src/task/base/AiVisionTask.ts
963
- import { convertImageDataToUseableForm } from "@workglow/util/media";
1000
+ // src/task/base/StreamingAiTask.ts
1001
+ import { getStreamingPorts, TaskConfigurationError as TaskConfigurationError3 } from "@workglow/task-graph";
964
1002
 
965
1003
  // src/task/base/AiTask.ts
966
1004
  import {
@@ -1146,7 +1184,393 @@ class AiTask extends Task {
1146
1184
  }
1147
1185
  }
1148
1186
 
1187
+ // src/task/base/StreamingAiTask.ts
1188
+ class StreamingAiTask extends AiTask {
1189
+ static type = "StreamingAiTask";
1190
+ async* executeStream(input, context) {
1191
+ const model = input.model;
1192
+ if (!model || typeof model !== "object") {
1193
+ throw new TaskConfigurationError3("StreamingAiTask: Model was not resolved to ModelConfig - this indicates a bug in the resolution system");
1194
+ }
1195
+ const jobInput = await this.getJobInput(input);
1196
+ const strategy = getAiProviderRegistry().getStrategy(model);
1197
+ const outSchema = this.outputSchema();
1198
+ const ports = getStreamingPorts(outSchema);
1199
+ let defaultPort = "text";
1200
+ if (ports.length > 0) {
1201
+ defaultPort = ports[0].port;
1202
+ } else {
1203
+ if (typeof outSchema === "object" && outSchema.properties) {
1204
+ const firstProp = Object.keys(outSchema.properties)[0];
1205
+ if (firstProp)
1206
+ defaultPort = firstProp;
1207
+ }
1208
+ }
1209
+ for await (const event of strategy.executeStream(jobInput, context, this.runConfig.runnerId)) {
1210
+ if (event.type === "text-delta") {
1211
+ yield { ...event, port: event.port ?? defaultPort };
1212
+ } else if (event.type === "object-delta") {
1213
+ yield { ...event, port: event.port ?? defaultPort };
1214
+ } else {
1215
+ yield event;
1216
+ }
1217
+ }
1218
+ }
1219
+ }
1220
+
1221
+ // src/task/ChatMessage.ts
1222
+ var ContentBlockTextSchema = {
1223
+ type: "object",
1224
+ properties: {
1225
+ type: { type: "string", enum: ["text"] },
1226
+ text: { type: "string" }
1227
+ },
1228
+ required: ["type", "text"],
1229
+ additionalProperties: false
1230
+ };
1231
+ var ContentBlockImageSchema = {
1232
+ type: "object",
1233
+ properties: {
1234
+ type: { type: "string", enum: ["image"] },
1235
+ mimeType: { type: "string" },
1236
+ data: { type: "string" }
1237
+ },
1238
+ required: ["type", "mimeType", "data"],
1239
+ additionalProperties: false
1240
+ };
1241
+ var ContentBlockToolUseSchema = {
1242
+ type: "object",
1243
+ properties: {
1244
+ type: { type: "string", enum: ["tool_use"] },
1245
+ id: { type: "string" },
1246
+ name: { type: "string" },
1247
+ input: { type: "object", additionalProperties: true }
1248
+ },
1249
+ required: ["type", "id", "name", "input"],
1250
+ additionalProperties: false
1251
+ };
1252
+ var ContentBlockToolResultSchema = {
1253
+ type: "object",
1254
+ properties: {
1255
+ type: { type: "string", enum: ["tool_result"] },
1256
+ tool_use_id: { type: "string" },
1257
+ content: {
1258
+ type: "array",
1259
+ items: { $ref: "#/definitions/ContentBlock" }
1260
+ },
1261
+ is_error: { type: "boolean" }
1262
+ },
1263
+ required: ["type", "tool_use_id", "content"],
1264
+ additionalProperties: false
1265
+ };
1266
+ var ContentBlockSchema = {
1267
+ oneOf: [
1268
+ ContentBlockTextSchema,
1269
+ ContentBlockImageSchema,
1270
+ ContentBlockToolUseSchema,
1271
+ ContentBlockToolResultSchema
1272
+ ],
1273
+ definitions: {
1274
+ ContentBlock: {
1275
+ oneOf: [
1276
+ ContentBlockTextSchema,
1277
+ ContentBlockImageSchema,
1278
+ ContentBlockToolUseSchema,
1279
+ ContentBlockToolResultSchema
1280
+ ]
1281
+ }
1282
+ },
1283
+ title: "ContentBlock",
1284
+ description: "A single content block within a chat message"
1285
+ };
1286
+ var ChatMessageSchema = {
1287
+ type: "object",
1288
+ properties: {
1289
+ role: { type: "string", enum: ["user", "assistant", "tool", "system"] },
1290
+ content: {
1291
+ type: "array",
1292
+ items: ContentBlockSchema
1293
+ }
1294
+ },
1295
+ required: ["role", "content"],
1296
+ additionalProperties: false,
1297
+ title: "ChatMessage",
1298
+ description: "A single chat message with role and structured content blocks"
1299
+ };
1300
+ function isContentBlock(value) {
1301
+ if (!value || typeof value !== "object")
1302
+ return false;
1303
+ const v = value;
1304
+ switch (v.type) {
1305
+ case "text":
1306
+ return typeof v.text === "string";
1307
+ case "image":
1308
+ return typeof v.mimeType === "string" && typeof v.data === "string";
1309
+ case "tool_use":
1310
+ return typeof v.id === "string" && typeof v.name === "string" && v.input !== null && typeof v.input === "object";
1311
+ case "tool_result":
1312
+ return typeof v.tool_use_id === "string" && Array.isArray(v.content) && v.content.every(isContentBlock);
1313
+ default:
1314
+ return false;
1315
+ }
1316
+ }
1317
+ function isChatMessage(value) {
1318
+ if (!value || typeof value !== "object")
1319
+ return false;
1320
+ const v = value;
1321
+ const validRole = v.role === "user" || v.role === "assistant" || v.role === "tool" || v.role === "system";
1322
+ return validRole && Array.isArray(v.content) && v.content.every(isContentBlock);
1323
+ }
1324
+ function textMessage(role, text) {
1325
+ return { role, content: [{ type: "text", text }] };
1326
+ }
1327
+
1328
+ // src/task/AiChatTask.ts
1329
+ import { resolveHumanConnector } from "@workglow/util";
1330
+ var modelSchema = TypeModel("model:AiChatTask");
1331
+ var chatConnectorContentSchema = {
1332
+ type: "object",
1333
+ properties: {
1334
+ content: {
1335
+ type: "string",
1336
+ title: "Message",
1337
+ description: "Your reply (leave blank to end the conversation)"
1338
+ }
1339
+ },
1340
+ additionalProperties: false
1341
+ };
1342
+ var AiChatInputSchema = {
1343
+ type: "object",
1344
+ properties: {
1345
+ model: modelSchema,
1346
+ prompt: {
1347
+ oneOf: [
1348
+ { type: "string", title: "Prompt", description: "The initial user message" },
1349
+ {
1350
+ type: "array",
1351
+ title: "Prompt",
1352
+ description: "The initial user message as structured content blocks",
1353
+ items: ContentBlockSchema
1354
+ }
1355
+ ],
1356
+ title: "Prompt",
1357
+ description: "The first user message to start the conversation"
1358
+ },
1359
+ messages: {
1360
+ type: "array",
1361
+ title: "Messages",
1362
+ description: "Conversation history (managed internally by the chat loop; not a user-facing input)",
1363
+ items: ChatMessageSchema,
1364
+ "x-ui-hidden": true
1365
+ },
1366
+ systemPrompt: {
1367
+ type: "string",
1368
+ title: "System Prompt",
1369
+ description: "Optional system instructions for the model"
1370
+ },
1371
+ maxTokens: {
1372
+ type: "number",
1373
+ title: "Max Tokens",
1374
+ description: "Per-turn token limit",
1375
+ minimum: 1,
1376
+ "x-ui-group": "Configuration"
1377
+ },
1378
+ temperature: {
1379
+ type: "number",
1380
+ title: "Temperature",
1381
+ description: "Sampling temperature",
1382
+ minimum: 0,
1383
+ maximum: 2,
1384
+ "x-ui-group": "Configuration"
1385
+ },
1386
+ maxIterations: {
1387
+ type: "number",
1388
+ title: "Max Iterations",
1389
+ description: "Safety cap on conversation turns",
1390
+ minimum: 1,
1391
+ default: 100,
1392
+ "x-ui-group": "Configuration"
1393
+ }
1394
+ },
1395
+ required: ["model", "prompt"],
1396
+ additionalProperties: false
1397
+ };
1398
+ var AiChatOutputSchema = {
1399
+ type: "object",
1400
+ properties: {
1401
+ text: {
1402
+ type: "string",
1403
+ title: "Text",
1404
+ description: "Last assistant response",
1405
+ "x-stream": "append"
1406
+ },
1407
+ messages: {
1408
+ type: "array",
1409
+ title: "Messages",
1410
+ description: "Full conversation history",
1411
+ items: ChatMessageSchema,
1412
+ "x-stream": "object"
1413
+ },
1414
+ iterations: {
1415
+ type: "number",
1416
+ title: "Iterations",
1417
+ description: "Number of completed turns"
1418
+ }
1419
+ },
1420
+ required: ["text", "messages", "iterations"],
1421
+ additionalProperties: false
1422
+ };
1423
+
1424
+ class AiChatTask extends StreamingAiTask {
1425
+ static type = "AiChatTask";
1426
+ static category = "AI Chat";
1427
+ static title = "AI Chat";
1428
+ static description = "Multi-turn chat with a language model, using a human connector to collect user input between turns.";
1429
+ static cacheable = false;
1430
+ static configSchema() {
1431
+ return {
1432
+ type: "object",
1433
+ properties: {
1434
+ ...TaskConfigSchema2["properties"]
1435
+ },
1436
+ additionalProperties: false
1437
+ };
1438
+ }
1439
+ static inputSchema() {
1440
+ return AiChatInputSchema;
1441
+ }
1442
+ static outputSchema() {
1443
+ return AiChatOutputSchema;
1444
+ }
1445
+ _sessionId;
1446
+ async getJobInput(input) {
1447
+ const model = input.model;
1448
+ if (!this._sessionId) {
1449
+ this._sessionId = getAiProviderRegistry().createSession(model.provider, model);
1450
+ }
1451
+ return {
1452
+ taskType: "AiChatTask",
1453
+ aiProvider: model.provider,
1454
+ taskInput: input,
1455
+ sessionId: this._sessionId
1456
+ };
1457
+ }
1458
+ async* executeStream(input, context) {
1459
+ this._sessionId = undefined;
1460
+ const model = input.model;
1461
+ if (!model || typeof model !== "object") {
1462
+ throw new Error("AiChatTask: model was not resolved to ModelConfig");
1463
+ }
1464
+ const connector = resolveHumanConnector(context);
1465
+ const history = [];
1466
+ if (input.systemPrompt) {
1467
+ history.push({ role: "system", content: [{ type: "text", text: input.systemPrompt }] });
1468
+ }
1469
+ const firstUserBlocks = typeof input.prompt === "string" ? [{ type: "text", text: input.prompt }] : input.prompt;
1470
+ history.push({ role: "user", content: firstUserBlocks });
1471
+ const workingInput = { ...input, messages: history };
1472
+ await this.getJobInput(workingInput);
1473
+ const strategy = getAiProviderRegistry().getStrategy(model);
1474
+ const maxIterations = input.maxIterations ?? 100;
1475
+ if (context.resourceScope && this._sessionId) {
1476
+ const sessionId = this._sessionId;
1477
+ context.resourceScope.register(`ai:session:${sessionId}`, async () => {
1478
+ await getAiProviderRegistry().disposeSession(model.provider, sessionId);
1479
+ });
1480
+ }
1481
+ yield {
1482
+ type: "object-delta",
1483
+ port: "messages",
1484
+ objectDelta: [...history]
1485
+ };
1486
+ let iterations = 0;
1487
+ let lastAssistantText = "";
1488
+ for (let turn = 0;turn < maxIterations; turn++) {
1489
+ const perTurnInput = { ...input, messages: [...history] };
1490
+ const turnJobInput = await this.getJobInput(perTurnInput);
1491
+ let assistantText = "";
1492
+ for await (const event of strategy.executeStream(turnJobInput, context, this.runConfig.runnerId)) {
1493
+ if (event.type === "text-delta") {
1494
+ assistantText += event.textDelta;
1495
+ yield {
1496
+ ...event,
1497
+ port: event.port ?? "text"
1498
+ };
1499
+ } else if (event.type === "finish") {} else {
1500
+ yield event;
1501
+ }
1502
+ }
1503
+ iterations++;
1504
+ lastAssistantText = assistantText;
1505
+ const assistantMsg = {
1506
+ role: "assistant",
1507
+ content: [{ type: "text", text: assistantText }]
1508
+ };
1509
+ history.push(assistantMsg);
1510
+ yield {
1511
+ type: "object-delta",
1512
+ port: "messages",
1513
+ objectDelta: [assistantMsg]
1514
+ };
1515
+ const request = {
1516
+ requestId: crypto.randomUUID(),
1517
+ targetHumanId: "default",
1518
+ kind: "elicit",
1519
+ message: "",
1520
+ contentSchema: chatConnectorContentSchema,
1521
+ contentData: undefined,
1522
+ expectsResponse: true,
1523
+ mode: "multi-turn",
1524
+ metadata: { iteration: turn, taskId: this.id }
1525
+ };
1526
+ const response = await connector.send(request, context.signal);
1527
+ if (response.action === "cancel" || response.action === "decline")
1528
+ break;
1529
+ const raw = response.content?.content;
1530
+ let userContent;
1531
+ if (typeof raw === "string") {
1532
+ const text = raw.trim();
1533
+ userContent = text.length > 0 ? [{ type: "text", text: raw }] : [];
1534
+ } else if (Array.isArray(raw)) {
1535
+ userContent = raw;
1536
+ } else {
1537
+ userContent = [];
1538
+ }
1539
+ if (userContent.length === 0)
1540
+ break;
1541
+ const userMsg = { role: "user", content: userContent };
1542
+ history.push(userMsg);
1543
+ yield {
1544
+ type: "object-delta",
1545
+ port: "messages",
1546
+ objectDelta: [userMsg]
1547
+ };
1548
+ }
1549
+ yield {
1550
+ type: "finish",
1551
+ data: {
1552
+ text: lastAssistantText,
1553
+ messages: [...history],
1554
+ iterations
1555
+ }
1556
+ };
1557
+ }
1558
+ async execute(input, context) {
1559
+ let result;
1560
+ for await (const event of this.executeStream(input, context)) {
1561
+ if (event.type === "finish") {
1562
+ result = event.data;
1563
+ }
1564
+ }
1565
+ return result;
1566
+ }
1567
+ }
1568
+
1569
+ // src/task/BackgroundRemovalTask.ts
1570
+ import { CreateWorkflow, Workflow } from "@workglow/task-graph";
1571
+
1149
1572
  // src/task/base/AiVisionTask.ts
1573
+ import { convertImageDataToUseableForm } from "@workglow/util/media";
1150
1574
  class AiVisionTask extends AiTask {
1151
1575
  static type = "AiVisionTask";
1152
1576
  async getJobInput(input) {
@@ -1167,7 +1591,7 @@ class AiVisionTask extends AiTask {
1167
1591
  }
1168
1592
 
1169
1593
  // src/task/BackgroundRemovalTask.ts
1170
- var modelSchema = TypeModel("model:BackgroundRemovalTask");
1594
+ var modelSchema2 = TypeModel("model:BackgroundRemovalTask");
1171
1595
  var processedImageSchema = {
1172
1596
  type: "string",
1173
1597
  contentEncoding: "base64",
@@ -1179,7 +1603,7 @@ var BackgroundRemovalInputSchema = {
1179
1603
  type: "object",
1180
1604
  properties: {
1181
1605
  image: TypeImageInput,
1182
- model: modelSchema
1606
+ model: modelSchema2
1183
1607
  },
1184
1608
  required: ["image", "model"],
1185
1609
  additionalProperties: false
@@ -1223,7 +1647,7 @@ import { CreateWorkflow as CreateWorkflow2, Workflow as Workflow2 } from "@workg
1223
1647
  import {
1224
1648
  TypedArraySchema
1225
1649
  } from "@workglow/util/schema";
1226
- var modelSchema2 = TypeModel("model:TextEmbeddingTask");
1650
+ var modelSchema3 = TypeModel("model:TextEmbeddingTask");
1227
1651
  var TextEmbeddingInputSchema = {
1228
1652
  type: "object",
1229
1653
  properties: {
@@ -1232,7 +1656,7 @@ var TextEmbeddingInputSchema = {
1232
1656
  title: "Text",
1233
1657
  description: "The text to embed"
1234
1658
  }),
1235
- model: modelSchema2
1659
+ model: modelSchema3
1236
1660
  },
1237
1661
  required: ["text", "model"],
1238
1662
  additionalProperties: false
@@ -2001,7 +2425,7 @@ import { CreateWorkflow as CreateWorkflow9, Task as Task7, Workflow as Workflow9
2001
2425
 
2002
2426
  // src/task/CountTokensTask.ts
2003
2427
  import { CreateWorkflow as CreateWorkflow8, Workflow as Workflow8 } from "@workglow/task-graph";
2004
- var modelSchema3 = TypeModel("model");
2428
+ var modelSchema4 = TypeModel("model");
2005
2429
  var CountTokensInputSchema = {
2006
2430
  type: "object",
2007
2431
  properties: {
@@ -2010,7 +2434,7 @@ var CountTokensInputSchema = {
2010
2434
  title: "Text",
2011
2435
  description: "The text to count tokens for"
2012
2436
  },
2013
- model: modelSchema3
2437
+ model: modelSchema4
2014
2438
  },
2015
2439
  required: ["text", "model"],
2016
2440
  additionalProperties: false
@@ -2054,7 +2478,7 @@ var ContextFormat = {
2054
2478
  MARKDOWN: "markdown",
2055
2479
  JSON: "json"
2056
2480
  };
2057
- var modelSchema4 = TypeModel("model", {
2481
+ var modelSchema5 = TypeModel("model", {
2058
2482
  title: "Model",
2059
2483
  description: "Model to use for token counting (optional, falls back to estimation)"
2060
2484
  });
@@ -2118,7 +2542,7 @@ var inputSchema6 = {
2118
2542
 
2119
2543
  `
2120
2544
  },
2121
- model: modelSchema4
2545
+ model: modelSchema5
2122
2546
  },
2123
2547
  required: ["chunks"],
2124
2548
  additionalProperties: false
@@ -2352,7 +2776,7 @@ import { CreateWorkflow as CreateWorkflow12, Task as Task8, Workflow as Workflow
2352
2776
 
2353
2777
  // src/task/TextNamedEntityRecognitionTask.ts
2354
2778
  import { CreateWorkflow as CreateWorkflow10, Workflow as Workflow10 } from "@workglow/task-graph";
2355
- var modelSchema5 = TypeModel("model:TextNamedEntityRecognitionTask");
2779
+ var modelSchema6 = TypeModel("model:TextNamedEntityRecognitionTask");
2356
2780
  var TextNamedEntityRecognitionInputSchema = {
2357
2781
  type: "object",
2358
2782
  properties: {
@@ -2371,7 +2795,7 @@ var TextNamedEntityRecognitionInputSchema = {
2371
2795
  "x-ui-group": "Configuration",
2372
2796
  "x-ui-group-open": false
2373
2797
  },
2374
- model: modelSchema5
2798
+ model: modelSchema6
2375
2799
  },
2376
2800
  required: ["text", "model"],
2377
2801
  additionalProperties: false
@@ -2430,44 +2854,7 @@ Workflow10.prototype.textNamedEntityRecognition = CreateWorkflow10(TextNamedEnti
2430
2854
 
2431
2855
  // src/task/TextSummaryTask.ts
2432
2856
  import { CreateWorkflow as CreateWorkflow11, Workflow as Workflow11 } from "@workglow/task-graph";
2433
-
2434
- // src/task/base/StreamingAiTask.ts
2435
- import { getStreamingPorts, TaskConfigurationError as TaskConfigurationError3 } from "@workglow/task-graph";
2436
- class StreamingAiTask extends AiTask {
2437
- static type = "StreamingAiTask";
2438
- async* executeStream(input, context) {
2439
- const model = input.model;
2440
- if (!model || typeof model !== "object") {
2441
- throw new TaskConfigurationError3("StreamingAiTask: Model was not resolved to ModelConfig - this indicates a bug in the resolution system");
2442
- }
2443
- const jobInput = await this.getJobInput(input);
2444
- const strategy = getAiProviderRegistry().getStrategy(model);
2445
- const outSchema = this.outputSchema();
2446
- const ports = getStreamingPorts(outSchema);
2447
- let defaultPort = "text";
2448
- if (ports.length > 0) {
2449
- defaultPort = ports[0].port;
2450
- } else {
2451
- if (typeof outSchema === "object" && outSchema.properties) {
2452
- const firstProp = Object.keys(outSchema.properties)[0];
2453
- if (firstProp)
2454
- defaultPort = firstProp;
2455
- }
2456
- }
2457
- for await (const event of strategy.executeStream(jobInput, context, this.runConfig.runnerId)) {
2458
- if (event.type === "text-delta") {
2459
- yield { ...event, port: event.port ?? defaultPort };
2460
- } else if (event.type === "object-delta") {
2461
- yield { ...event, port: event.port ?? defaultPort };
2462
- } else {
2463
- yield event;
2464
- }
2465
- }
2466
- }
2467
- }
2468
-
2469
- // src/task/TextSummaryTask.ts
2470
- var modelSchema6 = TypeModel("model:TextSummaryTask");
2857
+ var modelSchema7 = TypeModel("model:TextSummaryTask");
2471
2858
  var TextSummaryInputSchema = {
2472
2859
  type: "object",
2473
2860
  properties: {
@@ -2476,7 +2863,7 @@ var TextSummaryInputSchema = {
2476
2863
  title: "Text",
2477
2864
  description: "The text to summarize"
2478
2865
  },
2479
- model: modelSchema6
2866
+ model: modelSchema7
2480
2867
  },
2481
2868
  required: ["text", "model"],
2482
2869
  additionalProperties: false
@@ -2830,11 +3217,11 @@ Workflow13.prototype.documentUpsert = CreateWorkflow13(DocumentUpsertTask);
2830
3217
 
2831
3218
  // src/task/DownloadModelTask.ts
2832
3219
  import { CreateWorkflow as CreateWorkflow14, Workflow as Workflow14 } from "@workglow/task-graph";
2833
- var modelSchema7 = TypeModel("model");
3220
+ var modelSchema8 = TypeModel("model");
2834
3221
  var DownloadModelInputSchema = {
2835
3222
  type: "object",
2836
3223
  properties: {
2837
- model: modelSchema7
3224
+ model: modelSchema8
2838
3225
  },
2839
3226
  required: ["model"],
2840
3227
  additionalProperties: false
@@ -2842,7 +3229,7 @@ var DownloadModelInputSchema = {
2842
3229
  var DownloadModelOutputSchema = {
2843
3230
  type: "object",
2844
3231
  properties: {
2845
- model: modelSchema7
3232
+ model: modelSchema8
2846
3233
  },
2847
3234
  required: ["model"],
2848
3235
  additionalProperties: false
@@ -2900,7 +3287,7 @@ Workflow14.prototype.downloadModel = CreateWorkflow14(DownloadModelTask);
2900
3287
 
2901
3288
  // src/task/FaceDetectorTask.ts
2902
3289
  import { CreateWorkflow as CreateWorkflow15, Workflow as Workflow15 } from "@workglow/task-graph";
2903
- var modelSchema8 = TypeModel("model:FaceDetectorTask");
3290
+ var modelSchema9 = TypeModel("model:FaceDetectorTask");
2904
3291
  var TypeBoundingBox2 = {
2905
3292
  type: "object",
2906
3293
  properties: {
@@ -2973,7 +3360,7 @@ var FaceDetectorInputSchema = {
2973
3360
  type: "object",
2974
3361
  properties: {
2975
3362
  image: TypeImageInput,
2976
- model: modelSchema8,
3363
+ model: modelSchema9,
2977
3364
  minDetectionConfidence: {
2978
3365
  type: "number",
2979
3366
  minimum: 0,
@@ -3031,7 +3418,7 @@ Workflow15.prototype.faceDetector = CreateWorkflow15(FaceDetectorTask);
3031
3418
 
3032
3419
  // src/task/FaceLandmarkerTask.ts
3033
3420
  import { CreateWorkflow as CreateWorkflow16, Workflow as Workflow16 } from "@workglow/task-graph";
3034
- var modelSchema9 = TypeModel("model:FaceLandmarkerTask");
3421
+ var modelSchema10 = TypeModel("model:FaceLandmarkerTask");
3035
3422
  var TypeLandmark = {
3036
3423
  type: "object",
3037
3424
  properties: {
@@ -3103,7 +3490,7 @@ var FaceLandmarkerInputSchema = {
3103
3490
  type: "object",
3104
3491
  properties: {
3105
3492
  image: TypeImageInput,
3106
- model: modelSchema9,
3493
+ model: modelSchema10,
3107
3494
  numFaces: {
3108
3495
  type: "number",
3109
3496
  minimum: 1,
@@ -3193,7 +3580,7 @@ Workflow16.prototype.faceLandmarker = CreateWorkflow16(FaceLandmarkerTask);
3193
3580
 
3194
3581
  // src/task/GestureRecognizerTask.ts
3195
3582
  import { CreateWorkflow as CreateWorkflow17, Workflow as Workflow17 } from "@workglow/task-graph";
3196
- var modelSchema10 = TypeModel("model:GestureRecognizerTask");
3583
+ var modelSchema11 = TypeModel("model:GestureRecognizerTask");
3197
3584
  var TypeLandmark2 = {
3198
3585
  type: "object",
3199
3586
  properties: {
@@ -3285,7 +3672,7 @@ var GestureRecognizerInputSchema = {
3285
3672
  type: "object",
3286
3673
  properties: {
3287
3674
  image: TypeImageInput,
3288
- model: modelSchema10,
3675
+ model: modelSchema11,
3289
3676
  numHands: {
3290
3677
  type: "number",
3291
3678
  minimum: 1,
@@ -3361,7 +3748,7 @@ Workflow17.prototype.gestureRecognizer = CreateWorkflow17(GestureRecognizerTask)
3361
3748
 
3362
3749
  // src/task/HandLandmarkerTask.ts
3363
3750
  import { CreateWorkflow as CreateWorkflow18, Workflow as Workflow18 } from "@workglow/task-graph";
3364
- var modelSchema11 = TypeModel("model:HandLandmarkerTask");
3751
+ var modelSchema12 = TypeModel("model:HandLandmarkerTask");
3365
3752
  var TypeLandmark3 = {
3366
3753
  type: "object",
3367
3754
  properties: {
@@ -3430,7 +3817,7 @@ var HandLandmarkerInputSchema = {
3430
3817
  type: "object",
3431
3818
  properties: {
3432
3819
  image: TypeImageInput,
3433
- model: modelSchema11,
3820
+ model: modelSchema12,
3434
3821
  numHands: {
3435
3822
  type: "number",
3436
3823
  minimum: 1,
@@ -3513,7 +3900,7 @@ import {
3513
3900
  } from "@workglow/knowledge-base";
3514
3901
  import { CreateWorkflow as CreateWorkflow19, Task as Task10, Workflow as Workflow19 } from "@workglow/task-graph";
3515
3902
  import { uuid4 } from "@workglow/util";
3516
- var modelSchema12 = TypeModel("model", {
3903
+ var modelSchema13 = TypeModel("model", {
3517
3904
  title: "Model",
3518
3905
  description: "Model to use for token counting"
3519
3906
  });
@@ -3559,7 +3946,7 @@ var inputSchema9 = {
3559
3946
  description: "Strategy for chunking",
3560
3947
  default: "hierarchical"
3561
3948
  },
3562
- model: modelSchema12
3949
+ model: modelSchema13
3563
3950
  },
3564
3951
  required: ["doc_id", "documentTree"],
3565
3952
  additionalProperties: false
@@ -4004,12 +4391,12 @@ Workflow21.prototype.kbToDocuments = CreateWorkflow21(KbToDocumentsTask);
4004
4391
 
4005
4392
  // src/task/ImageClassificationTask.ts
4006
4393
  import { CreateWorkflow as CreateWorkflow22, Workflow as Workflow22 } from "@workglow/task-graph";
4007
- var modelSchema13 = TypeModel("model:ImageClassificationTask");
4394
+ var modelSchema14 = TypeModel("model:ImageClassificationTask");
4008
4395
  var ImageClassificationInputSchema = {
4009
4396
  type: "object",
4010
4397
  properties: {
4011
4398
  image: TypeImageInput,
4012
- model: modelSchema13,
4399
+ model: modelSchema14,
4013
4400
  categories: {
4014
4401
  type: "array",
4015
4402
  items: {
@@ -4070,12 +4457,12 @@ import { CreateWorkflow as CreateWorkflow23, Workflow as Workflow23 } from "@wor
4070
4457
  import {
4071
4458
  TypedArraySchema as TypedArraySchema7
4072
4459
  } from "@workglow/util/schema";
4073
- var modelSchema14 = TypeModel("model:ImageEmbeddingTask");
4460
+ var modelSchema15 = TypeModel("model:ImageEmbeddingTask");
4074
4461
  var ImageEmbeddingInputSchema = {
4075
4462
  type: "object",
4076
4463
  properties: {
4077
4464
  image: TypeSingleOrArray(TypeImageInput),
4078
- model: modelSchema14
4465
+ model: modelSchema15
4079
4466
  },
4080
4467
  required: ["image", "model"],
4081
4468
  additionalProperties: false
@@ -4111,12 +4498,12 @@ Workflow23.prototype.imageEmbedding = CreateWorkflow23(ImageEmbeddingTask);
4111
4498
 
4112
4499
  // src/task/ImageSegmentationTask.ts
4113
4500
  import { CreateWorkflow as CreateWorkflow24, Workflow as Workflow24 } from "@workglow/task-graph";
4114
- var modelSchema15 = TypeModel("model:ImageSegmentationTask");
4501
+ var modelSchema16 = TypeModel("model:ImageSegmentationTask");
4115
4502
  var ImageSegmentationInputSchema = {
4116
4503
  type: "object",
4117
4504
  properties: {
4118
4505
  image: TypeImageInput,
4119
- model: modelSchema15,
4506
+ model: modelSchema16,
4120
4507
  threshold: {
4121
4508
  type: "number",
4122
4509
  title: "Threshold",
@@ -4199,7 +4586,7 @@ Workflow24.prototype.imageSegmentation = CreateWorkflow24(ImageSegmentationTask)
4199
4586
 
4200
4587
  // src/task/ImageToTextTask.ts
4201
4588
  import { CreateWorkflow as CreateWorkflow25, Workflow as Workflow25 } from "@workglow/task-graph";
4202
- var modelSchema16 = TypeModel("model:ImageToTextTask");
4589
+ var modelSchema17 = TypeModel("model:ImageToTextTask");
4203
4590
  var generatedTextSchema = {
4204
4591
  type: "string",
4205
4592
  title: "Text",
@@ -4209,7 +4596,7 @@ var ImageToTextInputSchema = {
4209
4596
  type: "object",
4210
4597
  properties: {
4211
4598
  image: TypeImageInput,
4212
- model: modelSchema16,
4599
+ model: modelSchema17,
4213
4600
  maxTokens: {
4214
4601
  type: "number",
4215
4602
  title: "Max Tokens",
@@ -4254,11 +4641,11 @@ Workflow25.prototype.imageToText = CreateWorkflow25(ImageToTextTask);
4254
4641
 
4255
4642
  // src/task/ModelInfoTask.ts
4256
4643
  import { CreateWorkflow as CreateWorkflow26, Workflow as Workflow26 } from "@workglow/task-graph";
4257
- var modelSchema17 = TypeModel("model");
4644
+ var modelSchema18 = TypeModel("model");
4258
4645
  var ModelInfoInputSchema = {
4259
4646
  type: "object",
4260
4647
  properties: {
4261
- model: modelSchema17,
4648
+ model: modelSchema18,
4262
4649
  detail: {
4263
4650
  type: "string",
4264
4651
  enum: ["cached_status", "files", "files_with_metadata", "dimensions"],
@@ -4271,7 +4658,7 @@ var ModelInfoInputSchema = {
4271
4658
  var ModelInfoOutputSchema = {
4272
4659
  type: "object",
4273
4660
  properties: {
4274
- model: modelSchema17,
4661
+ model: modelSchema18,
4275
4662
  is_local: { type: "boolean" },
4276
4663
  is_remote: { type: "boolean" },
4277
4664
  supports_browser: { type: "boolean" },
@@ -4427,7 +4814,7 @@ Workflow27.prototype.modelSearch = CreateWorkflow27(ModelSearchTask);
4427
4814
 
4428
4815
  // src/task/ObjectDetectionTask.ts
4429
4816
  import { CreateWorkflow as CreateWorkflow28, Workflow as Workflow28 } from "@workglow/task-graph";
4430
- var modelSchema18 = TypeModel("model:ObjectDetectionTask");
4817
+ var modelSchema19 = TypeModel("model:ObjectDetectionTask");
4431
4818
  var detectionSchema = {
4432
4819
  type: "object",
4433
4820
  properties: {
@@ -4452,7 +4839,7 @@ var ObjectDetectionInputSchema = {
4452
4839
  type: "object",
4453
4840
  properties: {
4454
4841
  image: TypeImageInput,
4455
- model: modelSchema18,
4842
+ model: modelSchema19,
4456
4843
  labels: {
4457
4844
  type: "array",
4458
4845
  items: {
@@ -4510,7 +4897,7 @@ Workflow28.prototype.objectDetection = CreateWorkflow28(ObjectDetectionTask);
4510
4897
 
4511
4898
  // src/task/PoseLandmarkerTask.ts
4512
4899
  import { CreateWorkflow as CreateWorkflow29, Workflow as Workflow29 } from "@workglow/task-graph";
4513
- var modelSchema19 = TypeModel("model:PoseLandmarkerTask");
4900
+ var modelSchema20 = TypeModel("model:PoseLandmarkerTask");
4514
4901
  var TypePoseLandmark = {
4515
4902
  type: "object",
4516
4903
  properties: {
@@ -4589,7 +4976,7 @@ var PoseLandmarkerInputSchema = {
4589
4976
  type: "object",
4590
4977
  properties: {
4591
4978
  image: TypeImageInput,
4592
- model: modelSchema19,
4979
+ model: modelSchema20,
4593
4980
  numPoses: {
4594
4981
  type: "number",
4595
4982
  minimum: 1,
@@ -4888,7 +5275,7 @@ import { CreateWorkflow as CreateWorkflow32, Task as Task15, Workflow as Workflo
4888
5275
 
4889
5276
  // src/task/TextClassificationTask.ts
4890
5277
  import { CreateWorkflow as CreateWorkflow31, Workflow as Workflow31 } from "@workglow/task-graph";
4891
- var modelSchema20 = TypeModel("model:TextClassificationTask");
5278
+ var modelSchema21 = TypeModel("model:TextClassificationTask");
4892
5279
  var TextClassificationInputSchema = {
4893
5280
  type: "object",
4894
5281
  properties: {
@@ -4915,7 +5302,7 @@ var TextClassificationInputSchema = {
4915
5302
  description: "The maximum number of categories to return",
4916
5303
  "x-ui-group": "Configuration"
4917
5304
  },
4918
- model: modelSchema20
5305
+ model: modelSchema21
4919
5306
  },
4920
5307
  required: ["text", "model"],
4921
5308
  additionalProperties: false
@@ -5298,12 +5685,13 @@ var structuralParser = (input, config) => {
5298
5685
  Workflow33.prototype.structuralParser = CreateWorkflow33(StructuralParserTask);
5299
5686
 
5300
5687
  // src/task/StructuredGenerationTask.ts
5301
- import { CreateWorkflow as CreateWorkflow34, Workflow as Workflow34 } from "@workglow/task-graph";
5302
- var modelSchema21 = TypeModel("model:StructuredGenerationTask");
5688
+ import { CreateWorkflow as CreateWorkflow34, TaskConfigurationError as TaskConfigurationError4, TaskError, Workflow as Workflow34 } from "@workglow/task-graph";
5689
+ import { compileSchema as compileSchema2 } from "@workglow/util/schema";
5690
+ var modelSchema22 = TypeModel("model:StructuredGenerationTask");
5303
5691
  var StructuredGenerationInputSchema = {
5304
5692
  type: "object",
5305
5693
  properties: {
5306
- model: modelSchema21,
5694
+ model: modelSchema22,
5307
5695
  prompt: {
5308
5696
  type: "string",
5309
5697
  title: "Prompt",
@@ -5330,6 +5718,15 @@ var StructuredGenerationInputSchema = {
5330
5718
  minimum: 0,
5331
5719
  maximum: 2,
5332
5720
  "x-ui-group": "Configuration"
5721
+ },
5722
+ maxRetries: {
5723
+ type: "integer",
5724
+ title: "Max Retries",
5725
+ description: "Number of times to re-prompt the model with validation errors when its output doesn't match the schema. 0 disables retries (fail on first mismatch).",
5726
+ minimum: 0,
5727
+ maximum: 10,
5728
+ default: 2,
5729
+ "x-ui-group": "Configuration"
5333
5730
  }
5334
5731
  },
5335
5732
  required: ["model", "prompt", "outputSchema"],
@@ -5351,17 +5748,111 @@ var StructuredGenerationOutputSchema = {
5351
5748
  additionalProperties: false
5352
5749
  };
5353
5750
 
5751
+ class StructuredOutputValidationError extends TaskError {
5752
+ static type = "StructuredOutputValidationError";
5753
+ attempts;
5754
+ constructor(attempts) {
5755
+ const last = attempts[attempts.length - 1];
5756
+ const summary = last?.errors.map((e) => `${e.path || "/"}: ${e.message}`).join("; ") ?? "";
5757
+ super(`StructuredGenerationTask: model output failed validation after ${attempts.length} attempt(s). ` + `Last errors: ${summary}`);
5758
+ this.attempts = attempts;
5759
+ }
5760
+ }
5761
+ function validationErrorsFromSchemaNode(result) {
5762
+ return result.errors.map((e) => ({ path: e.data.pointer || "", message: e.message }));
5763
+ }
5764
+ function buildRetryPrompt(originalPrompt, errors) {
5765
+ const errorList = errors.map((e) => ` - ${e.path || "/"}: ${e.message}`).join(`
5766
+ `);
5767
+ return `${originalPrompt}
5768
+
5769
+ ` + `Your previous response did not conform to the required JSON schema. ` + `Validation errors:
5770
+ ${errorList}
5771
+
5772
+ ` + `Please respond again with a JSON object that satisfies the schema. ` + `Output ONLY the JSON object, no other text.`;
5773
+ }
5774
+
5354
5775
  class StructuredGenerationTask extends StreamingAiTask {
5355
5776
  static type = "StructuredGenerationTask";
5356
5777
  static category = "AI Text Model";
5357
5778
  static title = "Structured Generation";
5358
- static description = "Generates structured JSON output conforming to a provided schema using language models";
5779
+ static description = "Generates structured JSON output conforming to a provided schema using language models, with automatic validation and retry on mismatch";
5359
5780
  static inputSchema() {
5360
5781
  return StructuredGenerationInputSchema;
5361
5782
  }
5362
5783
  static outputSchema() {
5363
5784
  return StructuredGenerationOutputSchema;
5364
5785
  }
5786
+ async* executeStream(input, context) {
5787
+ let validator;
5788
+ try {
5789
+ validator = compileSchema2(input.outputSchema);
5790
+ } catch (err2) {
5791
+ const msg = err2 instanceof Error ? err2.message : String(err2);
5792
+ const configErr = new TaskConfigurationError4(`StructuredGenerationTask: invalid outputSchema — ${msg}`);
5793
+ configErr.taskType = this.type;
5794
+ configErr.taskId = this.id;
5795
+ throw configErr;
5796
+ }
5797
+ const maxRetries = Math.max(0, input.maxRetries ?? 2);
5798
+ const maxAttempts = maxRetries + 1;
5799
+ const attempts = [];
5800
+ let currentInput = input;
5801
+ for (let attempt = 1;attempt <= maxAttempts; attempt++) {
5802
+ let lastObject;
5803
+ for await (const event of super.executeStream(currentInput, context)) {
5804
+ if (event.type === "object-delta" && event.port === "object") {
5805
+ const delta = event.objectDelta;
5806
+ if (delta && !Array.isArray(delta)) {
5807
+ lastObject = delta;
5808
+ }
5809
+ yield event;
5810
+ } else if (event.type === "finish") {
5811
+ const data = event.data;
5812
+ const finalObject = data?.object ?? lastObject ?? {};
5813
+ const result = validator.validate(finalObject);
5814
+ if (result.valid) {
5815
+ yield {
5816
+ type: "finish",
5817
+ data: { object: finalObject }
5818
+ };
5819
+ return;
5820
+ }
5821
+ const errors = validationErrorsFromSchemaNode(result);
5822
+ attempts.push({ attempt, errors, object: finalObject });
5823
+ lastObject = finalObject;
5824
+ break;
5825
+ } else {
5826
+ yield event;
5827
+ }
5828
+ }
5829
+ if (attempt < maxAttempts) {
5830
+ yield {
5831
+ type: "object-delta",
5832
+ port: "object",
5833
+ objectDelta: {}
5834
+ };
5835
+ const lastErrors = attempts[attempts.length - 1].errors;
5836
+ currentInput = {
5837
+ ...input,
5838
+ prompt: buildRetryPrompt(input.prompt, lastErrors)
5839
+ };
5840
+ }
5841
+ }
5842
+ const err = new StructuredOutputValidationError(attempts);
5843
+ err.taskType = this.type;
5844
+ err.taskId = this.id;
5845
+ throw err;
5846
+ }
5847
+ async execute(input, context) {
5848
+ let result;
5849
+ for await (const event of this.executeStream(input, context)) {
5850
+ if (event.type === "finish") {
5851
+ result = event.data;
5852
+ }
5853
+ }
5854
+ return result;
5855
+ }
5365
5856
  }
5366
5857
  var structuredGeneration = (input, config) => {
5367
5858
  return new StructuredGenerationTask(config).run(input);
@@ -5622,7 +6113,7 @@ Workflow35.prototype.textChunker = CreateWorkflow35(TextChunkerTask);
5622
6113
 
5623
6114
  // src/task/TextFillMaskTask.ts
5624
6115
  import { CreateWorkflow as CreateWorkflow36, Workflow as Workflow36 } from "@workglow/task-graph";
5625
- var modelSchema22 = TypeModel("model:TextFillMaskTask");
6116
+ var modelSchema23 = TypeModel("model:TextFillMaskTask");
5626
6117
  var TextFillMaskInputSchema = {
5627
6118
  type: "object",
5628
6119
  properties: {
@@ -5631,7 +6122,7 @@ var TextFillMaskInputSchema = {
5631
6122
  title: "Text",
5632
6123
  description: "The text with a mask token to fill"
5633
6124
  },
5634
- model: modelSchema22
6125
+ model: modelSchema23
5635
6126
  },
5636
6127
  required: ["text", "model"],
5637
6128
  additionalProperties: false
@@ -5696,11 +6187,11 @@ var generatedTextSchema2 = {
5696
6187
  description: "The generated text",
5697
6188
  "x-stream": "append"
5698
6189
  };
5699
- var modelSchema23 = TypeModel("model:TextGenerationTask");
6190
+ var modelSchema24 = TypeModel("model:TextGenerationTask");
5700
6191
  var TextGenerationInputSchema = {
5701
6192
  type: "object",
5702
6193
  properties: {
5703
- model: modelSchema23,
6194
+ model: modelSchema24,
5704
6195
  prompt: {
5705
6196
  type: "string",
5706
6197
  title: "Prompt",
@@ -5778,7 +6269,7 @@ Workflow37.prototype.textGeneration = CreateWorkflow37(TextGenerationTask);
5778
6269
 
5779
6270
  // src/task/TextLanguageDetectionTask.ts
5780
6271
  import { CreateWorkflow as CreateWorkflow38, Workflow as Workflow38 } from "@workglow/task-graph";
5781
- var modelSchema24 = TypeModel("model:TextLanguageDetectionTask");
6272
+ var modelSchema25 = TypeModel("model:TextLanguageDetectionTask");
5782
6273
  var TextLanguageDetectionInputSchema = {
5783
6274
  type: "object",
5784
6275
  properties: {
@@ -5795,7 +6286,7 @@ var TextLanguageDetectionInputSchema = {
5795
6286
  title: "Max Languages",
5796
6287
  description: "The maximum number of languages to return"
5797
6288
  },
5798
- model: modelSchema24
6289
+ model: modelSchema25
5799
6290
  },
5800
6291
  required: ["text", "model"],
5801
6292
  additionalProperties: false
@@ -5865,13 +6356,13 @@ var textSchema = {
5865
6356
  description: "The generated text",
5866
6357
  "x-stream": "append"
5867
6358
  };
5868
- var modelSchema25 = TypeModel("model:TextQuestionAnswerTask");
6359
+ var modelSchema26 = TypeModel("model:TextQuestionAnswerTask");
5869
6360
  var TextQuestionAnswerInputSchema = {
5870
6361
  type: "object",
5871
6362
  properties: {
5872
6363
  context: contextSchema,
5873
6364
  question: questionSchema,
5874
- model: modelSchema25
6365
+ model: modelSchema26
5875
6366
  },
5876
6367
  required: ["context", "question", "model"],
5877
6368
  additionalProperties: false
@@ -5904,7 +6395,7 @@ Workflow39.prototype.textQuestionAnswer = CreateWorkflow39(TextQuestionAnswerTas
5904
6395
 
5905
6396
  // src/task/TextRewriterTask.ts
5906
6397
  import { CreateWorkflow as CreateWorkflow40, Workflow as Workflow40 } from "@workglow/task-graph";
5907
- var modelSchema26 = TypeModel("model:TextRewriterTask");
6398
+ var modelSchema27 = TypeModel("model:TextRewriterTask");
5908
6399
  var TextRewriterInputSchema = {
5909
6400
  type: "object",
5910
6401
  properties: {
@@ -5918,7 +6409,7 @@ var TextRewriterInputSchema = {
5918
6409
  title: "Prompt",
5919
6410
  description: "The prompt to direct the rewriting"
5920
6411
  },
5921
- model: modelSchema26
6412
+ model: modelSchema27
5922
6413
  },
5923
6414
  required: ["text", "prompt", "model"],
5924
6415
  additionalProperties: false
@@ -5956,7 +6447,7 @@ Workflow40.prototype.textRewriter = CreateWorkflow40(TextRewriterTask);
5956
6447
 
5957
6448
  // src/task/TextTranslationTask.ts
5958
6449
  import { CreateWorkflow as CreateWorkflow41, Workflow as Workflow41 } from "@workglow/task-graph";
5959
- var modelSchema27 = TypeModel("model:TextTranslationTask");
6450
+ var modelSchema28 = TypeModel("model:TextTranslationTask");
5960
6451
  var translationTextSchema = {
5961
6452
  type: "string",
5962
6453
  title: "Text",
@@ -5983,7 +6474,7 @@ var TextTranslationInputSchema = {
5983
6474
  minLength: 2,
5984
6475
  maxLength: 2
5985
6476
  }),
5986
- model: modelSchema27
6477
+ model: modelSchema28
5987
6478
  },
5988
6479
  required: ["text", "source_lang", "target_lang", "model"],
5989
6480
  additionalProperties: false
@@ -6105,11 +6596,11 @@ var ToolCallSchema = {
6105
6596
  required: ["id", "name", "input"],
6106
6597
  additionalProperties: false
6107
6598
  };
6108
- var modelSchema28 = TypeModel("model:ToolCallingTask");
6599
+ var modelSchema29 = TypeModel("model:ToolCallingTask");
6109
6600
  var ToolCallingInputSchema = {
6110
6601
  type: "object",
6111
6602
  properties: {
6112
- model: modelSchema28,
6603
+ model: modelSchema29,
6113
6604
  prompt: {
6114
6605
  oneOf: [
6115
6606
  { type: "string", title: "Prompt", description: "The prompt to send to the model" },
@@ -6144,15 +6635,7 @@ var ToolCallingInputSchema = {
6144
6635
  type: "array",
6145
6636
  title: "Messages",
6146
6637
  description: "Full conversation history for multi-turn interactions. When provided, used instead of prompt to construct the messages array sent to the provider.",
6147
- items: {
6148
- type: "object",
6149
- properties: {
6150
- role: { type: "string", enum: ["user", "assistant", "tool"] },
6151
- content: {}
6152
- },
6153
- required: ["role", "content"],
6154
- additionalProperties: true
6155
- }
6638
+ items: ChatMessageSchema
6156
6639
  },
6157
6640
  tools: {
6158
6641
  type: "array",
@@ -6548,11 +7031,11 @@ Workflow43.prototype.topicSegmenter = CreateWorkflow43(TopicSegmenterTask);
6548
7031
 
6549
7032
  // src/task/UnloadModelTask.ts
6550
7033
  import { CreateWorkflow as CreateWorkflow44, Workflow as Workflow44 } from "@workglow/task-graph";
6551
- var modelSchema29 = TypeModel("model");
7034
+ var modelSchema30 = TypeModel("model");
6552
7035
  var UnloadModelInputSchema = {
6553
7036
  type: "object",
6554
7037
  properties: {
6555
- model: modelSchema29
7038
+ model: modelSchema30
6556
7039
  },
6557
7040
  required: ["model"],
6558
7041
  additionalProperties: false
@@ -6560,7 +7043,7 @@ var UnloadModelInputSchema = {
6560
7043
  var UnloadModelOutputSchema = {
6561
7044
  type: "object",
6562
7045
  properties: {
6563
- model: modelSchema29
7046
+ model: modelSchema30
6564
7047
  },
6565
7048
  required: ["model"],
6566
7049
  additionalProperties: false
@@ -6875,7 +7358,6 @@ var similarity = (input, config) => {
6875
7358
  return new VectorSimilarityTask(config).run(input);
6876
7359
  };
6877
7360
  Workflow46.prototype.similarity = CreateWorkflow46(VectorSimilarityTask);
6878
-
6879
7361
  // src/task/MessageConversion.ts
6880
7362
  function getInputMessages(input) {
6881
7363
  const messages = input.messages;
@@ -6924,66 +7406,46 @@ function toOpenAIMessages(input) {
6924
7406
  }
6925
7407
  for (const msg of inputMessages) {
6926
7408
  if (msg.role === "user") {
6927
- if (typeof msg.content === "string") {
6928
- messages.push({ role: "user", content: msg.content });
6929
- } else if (Array.isArray(msg.content) && msg.content.length > 0 && typeof msg.content[0]?.type === "string") {
6930
- const parts = [];
6931
- for (const block of msg.content) {
6932
- const b = block;
6933
- if (b.type === "text") {
6934
- parts.push({ type: "text", text: b.text });
6935
- } else if (b.type === "image") {
6936
- parts.push({
6937
- type: "image_url",
6938
- image_url: { url: `data:${b.mimeType};base64,${b.data}` }
6939
- });
6940
- } else if (b.type === "audio") {
6941
- const format = b.mimeType.replace(/^audio\//, "");
6942
- parts.push({
6943
- type: "input_audio",
6944
- input_audio: { data: b.data, format }
6945
- });
6946
- }
6947
- }
6948
- messages.push({ role: "user", content: parts });
6949
- } else {
6950
- try {
6951
- messages.push({ role: "user", content: JSON.stringify(msg.content) });
6952
- } catch {
6953
- messages.push({ role: "user", content: String(msg.content) });
7409
+ const parts = [];
7410
+ for (const block of msg.content) {
7411
+ if (block.type === "text") {
7412
+ parts.push({ type: "text", text: block.text });
7413
+ } else if (block.type === "image") {
7414
+ parts.push({
7415
+ type: "image_url",
7416
+ image_url: { url: `data:${block.mimeType};base64,${block.data}` }
7417
+ });
6954
7418
  }
6955
7419
  }
7420
+ messages.push({ role: "user", content: parts });
6956
7421
  } else if (msg.role === "assistant") {
6957
- if (typeof msg.content === "string") {
6958
- messages.push({ role: "assistant", content: msg.content.length > 0 ? msg.content : null });
6959
- } else if (Array.isArray(msg.content)) {
6960
- const textParts = msg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
6961
- const toolCalls = msg.content.filter((b) => b.type === "tool_use").map((b) => ({
6962
- id: b.id,
6963
- type: "function",
6964
- function: {
6965
- name: b.name,
6966
- arguments: JSON.stringify(b.input)
6967
- }
6968
- }));
6969
- const entry = {
6970
- role: "assistant",
6971
- content: textParts.length > 0 ? textParts : null
6972
- };
6973
- if (toolCalls.length > 0) {
6974
- entry.tool_calls = toolCalls;
7422
+ const textParts = msg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
7423
+ const toolCalls = msg.content.filter((b) => b.type === "tool_use").map((b) => ({
7424
+ id: b.id,
7425
+ type: "function",
7426
+ function: {
7427
+ name: b.name,
7428
+ arguments: JSON.stringify(b.input)
6975
7429
  }
6976
- messages.push(entry);
7430
+ }));
7431
+ const entry = {
7432
+ role: "assistant",
7433
+ content: textParts.length > 0 ? textParts : null
7434
+ };
7435
+ if (toolCalls.length > 0) {
7436
+ entry.tool_calls = toolCalls;
6977
7437
  }
6978
- } else if (msg.role === "tool" && Array.isArray(msg.content)) {
7438
+ messages.push(entry);
7439
+ } else if (msg.role === "tool") {
6979
7440
  for (const block of msg.content) {
6980
- const b = block;
7441
+ if (block.type !== "tool_result")
7442
+ continue;
6981
7443
  let content;
6982
- if (typeof b.content === "string") {
6983
- content = b.content;
6984
- } else if (Array.isArray(b.content)) {
7444
+ if (block.content.length === 1 && block.content[0].type === "text") {
7445
+ content = block.content[0].text;
7446
+ } else {
6985
7447
  const parts = [];
6986
- for (const inner of b.content) {
7448
+ for (const inner of block.content) {
6987
7449
  if (inner.type === "text") {
6988
7450
  parts.push({ type: "text", text: inner.text });
6989
7451
  } else if (inner.type === "image") {
@@ -6994,14 +7456,8 @@ function toOpenAIMessages(input) {
6994
7456
  }
6995
7457
  }
6996
7458
  content = parts;
6997
- } else {
6998
- content = "";
6999
7459
  }
7000
- messages.push({
7001
- role: "tool",
7002
- content,
7003
- tool_call_id: b.tool_use_id
7004
- });
7460
+ messages.push({ role: "tool", content, tool_call_id: block.tool_use_id });
7005
7461
  }
7006
7462
  }
7007
7463
  }
@@ -7031,41 +7487,18 @@ function toTextFlatMessages(input) {
7031
7487
  }
7032
7488
  for (const msg of inputMessages) {
7033
7489
  if (msg.role === "user") {
7034
- let content = "";
7035
- if (typeof msg.content === "string") {
7036
- content = msg.content;
7037
- } else if (Array.isArray(msg.content) && msg.content.length > 0 && typeof msg.content[0]?.type === "string") {
7038
- content = msg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
7039
- } else if (msg.content != null) {
7040
- try {
7041
- content = JSON.stringify(msg.content);
7042
- } catch {
7043
- content = String(msg.content);
7044
- }
7045
- }
7490
+ const content = msg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
7046
7491
  messages.push({ role: "user", content });
7047
7492
  } else if (msg.role === "assistant") {
7048
- if (typeof msg.content === "string") {
7049
- if (msg.content) {
7050
- messages.push({ role: "assistant", content: msg.content });
7051
- }
7052
- } else if (Array.isArray(msg.content)) {
7053
- const text = msg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
7054
- if (text) {
7055
- messages.push({ role: "assistant", content: text });
7056
- }
7493
+ const text = msg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
7494
+ if (text) {
7495
+ messages.push({ role: "assistant", content: text });
7057
7496
  }
7058
- } else if (msg.role === "tool" && Array.isArray(msg.content)) {
7497
+ } else if (msg.role === "tool") {
7059
7498
  for (const block of msg.content) {
7060
- const b = block;
7061
- let content;
7062
- if (typeof b.content === "string") {
7063
- content = b.content;
7064
- } else if (Array.isArray(b.content)) {
7065
- content = b.content.filter((inner) => inner.type === "text").map((inner) => inner.text).join("");
7066
- } else {
7067
- content = "";
7068
- }
7499
+ if (block.type !== "tool_result")
7500
+ continue;
7501
+ const content = block.content.filter((inner) => inner.type === "text").map((inner) => inner.text).join("");
7069
7502
  messages.push({ role: "tool", content });
7070
7503
  }
7071
7504
  }
@@ -7076,6 +7509,7 @@ function toTextFlatMessages(input) {
7076
7509
  // src/task/index.ts
7077
7510
  var registerAiTasks = () => {
7078
7511
  const tasks = [
7512
+ AiChatTask,
7079
7513
  BackgroundRemovalTask,
7080
7514
  ChunkToVectorTask,
7081
7515
  CountTokensTask,
@@ -7139,6 +7573,7 @@ export {
7139
7573
  textRewriter,
7140
7574
  textQuestionAnswer,
7141
7575
  textNamedEntityRecognition,
7576
+ textMessage,
7142
7577
  textLanguageDetection,
7143
7578
  textGeneration,
7144
7579
  textFillMask,
@@ -7160,6 +7595,8 @@ export {
7160
7595
  modelSearch,
7161
7596
  modelInfo,
7162
7597
  kbToDocuments,
7598
+ isContentBlock,
7599
+ isChatMessage,
7163
7600
  isAllowedToolName,
7164
7601
  imageToText,
7165
7602
  imageSegmentation,
@@ -7233,6 +7670,7 @@ export {
7233
7670
  TextClassificationOutputSchema,
7234
7671
  TextClassificationInputSchema,
7235
7672
  TextChunkerTask,
7673
+ StructuredOutputValidationError,
7236
7674
  StructuredGenerationTask,
7237
7675
  StructuredGenerationOutputSchema,
7238
7676
  StructuredGenerationInputSchema,
@@ -7296,19 +7734,24 @@ export {
7296
7734
  CountTokensInputSchema,
7297
7735
  ContextFormat,
7298
7736
  ContextBuilderTask,
7737
+ ContentBlockSchema,
7299
7738
  ChunkingStrategy,
7300
7739
  ChunkVectorUpsertTask,
7301
7740
  ChunkVectorSearchTask,
7302
7741
  ChunkVectorHybridSearchTask,
7303
7742
  ChunkToVectorTask,
7304
7743
  ChunkRetrievalTask,
7744
+ ChatMessageSchema,
7305
7745
  BackgroundRemovalTask,
7306
7746
  BackgroundRemovalOutputSchema,
7307
7747
  BackgroundRemovalInputSchema,
7308
7748
  AiTask,
7309
7749
  AiProviderRegistry,
7310
7750
  AiProvider,
7311
- AiJob
7751
+ AiJob,
7752
+ AiChatTask,
7753
+ AiChatOutputSchema,
7754
+ AiChatInputSchema
7312
7755
  };
7313
7756
 
7314
- //# debugId=B7418C4E521F738364756E2164756E21
7757
+ //# debugId=CA8AB8D417D38A5264756E2164756E21