@workglow/task-graph 0.2.17 → 0.2.19

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/common.d.ts CHANGED
@@ -20,9 +20,12 @@ export * from "./task-graph/TransformRegistry";
20
20
  export * from "./task-graph/TransformTypes";
21
21
  export * from "./task-graph/transforms";
22
22
  export * from "./task-graph/autoConnect";
23
+ export { registerRefcountablePredicate, asRefcountable, _resetRefcountablePredicatesForTests, type Refcountable, } from "./refcountable";
23
24
  export * from "./task";
24
25
  export * from "./storage/TaskGraphRepository";
25
26
  export * from "./storage/TaskGraphTabularRepository";
26
27
  export * from "./storage/TaskOutputRepository";
27
28
  export * from "./storage/TaskOutputTabularRepository";
29
+ export { registerPortCodec, getPortCodec, _resetPortCodecsForTests } from "./storage/PortCodecRegistry";
30
+ export type { PortCodec } from "./storage/PortCodecRegistry";
28
31
  //# sourceMappingURL=common.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../src/common.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAE5C,cAAc,oCAAoC,CAAC;AACnD,cAAc,iCAAiC,CAAC;AAChD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,8BAA8B,CAAC;AAE7C,cAAc,0BAA0B,CAAC;AACzC,cAAc,kCAAkC,CAAC;AACjD,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AAEtC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AAEzC,cAAc,QAAQ,CAAC;AAEvB,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sCAAsC,CAAC;AACrD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uCAAuC,CAAC"}
1
+ {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../src/common.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAE5C,cAAc,oCAAoC,CAAC;AACnD,cAAc,iCAAiC,CAAC;AAChD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,8BAA8B,CAAC;AAE7C,cAAc,0BAA0B,CAAC;AACzC,cAAc,kCAAkC,CAAC;AACjD,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AAEtC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AAEzC,OAAO,EACL,6BAA6B,EAC7B,cAAc,EACd,oCAAoC,EACpC,KAAK,YAAY,GAClB,MAAM,gBAAgB,CAAC;AAExB,cAAc,QAAQ,CAAC;AAEvB,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sCAAsC,CAAC;AACrD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uCAAuC,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AACxG,YAAY,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC"}
package/dist/node.js CHANGED
@@ -584,6 +584,10 @@ function computeGraphEntitlements(graph, options) {
584
584
  }
585
585
  // src/task/InputResolver.ts
586
586
  import { getInputResolvers } from "@workglow/util";
587
+ function isPlainObject(value) {
588
+ const proto = Object.getPrototypeOf(value);
589
+ return proto === Object.prototype || proto === null;
590
+ }
587
591
  function getSchemaFormat(schema, visited = new WeakSet) {
588
592
  if (typeof schema !== "object" || schema === null)
589
593
  return;
@@ -671,6 +675,7 @@ async function resolveSchemaInputs(input, schema, config, visited = new Set) {
671
675
  for (const [key, propSchema] of Object.entries(properties)) {
672
676
  let value = resolved[key];
673
677
  const format = getSchemaFormat(propSchema);
678
+ let phase1Transformed = false;
674
679
  if (format) {
675
680
  let resolver = resolvers.get(format);
676
681
  if (!resolver) {
@@ -681,14 +686,18 @@ async function resolveSchemaInputs(input, schema, config, visited = new Set) {
681
686
  if (typeof value === "string") {
682
687
  value = await resolver(value, format, config.registry);
683
688
  resolved[key] = value;
689
+ phase1Transformed = true;
684
690
  } else if (Array.isArray(value) && value.some((item) => typeof item === "string")) {
685
691
  const results = await Promise.all(value.map((item) => typeof item === "string" ? resolver(item, format, config.registry) : item));
686
692
  value = results.filter((result) => result !== undefined);
687
693
  resolved[key] = value;
694
+ phase1Transformed = true;
688
695
  }
689
696
  }
690
697
  }
691
- if (value !== null && value !== undefined && typeof value === "object" && !Array.isArray(value)) {
698
+ const hasFormatResolver = format ? !!(resolvers.get(format) ?? resolvers.get(getFormatPrefix(format))) : false;
699
+ const skipPhase2 = hasFormatResolver && !phase1Transformed;
700
+ if (!skipPhase2 && value !== null && value !== undefined && typeof value === "object" && !Array.isArray(value) && isPlainObject(value)) {
692
701
  const objectSchema = getObjectSchema(propSchema);
693
702
  if (objectSchema && !visited.has(objectSchema)) {
694
703
  visited.add(objectSchema);
@@ -1134,6 +1143,31 @@ import {
1134
1143
  uuid4 as uuid43
1135
1144
  } from "@workglow/util";
1136
1145
 
1146
+ // src/refcountable.ts
1147
+ var GLOBAL_KEY = Symbol.for("@workglow/task-graph/refcountable.predicates");
1148
+ var _g = globalThis;
1149
+ if (!Array.isArray(_g[GLOBAL_KEY])) {
1150
+ _g[GLOBAL_KEY] = [];
1151
+ }
1152
+ var predicates = _g[GLOBAL_KEY];
1153
+ function registerRefcountablePredicate(p) {
1154
+ predicates.push(p);
1155
+ }
1156
+ function asRefcountable(v) {
1157
+ if (v === null || v === undefined)
1158
+ return null;
1159
+ if (typeof v !== "object")
1160
+ return null;
1161
+ for (const p of predicates) {
1162
+ if (p(v))
1163
+ return v;
1164
+ }
1165
+ return null;
1166
+ }
1167
+ function _resetRefcountablePredicatesForTests() {
1168
+ predicates.length = 0;
1169
+ }
1170
+
1137
1171
  // src/storage/TaskOutputRepository.ts
1138
1172
  import { createServiceToken as createServiceToken2, EventEmitter as EventEmitter2 } from "@workglow/util";
1139
1173
  var TASK_OUTPUT_REPOSITORY = createServiceToken2("taskgraph.taskOutputRepository");
@@ -1245,6 +1279,7 @@ import {
1245
1279
  globalServiceRegistry as globalServiceRegistry2,
1246
1280
  SpanStatusCode
1247
1281
  } from "@workglow/util";
1282
+ import { getPortCodec } from "@workglow/util";
1248
1283
 
1249
1284
  // src/task/StreamTypes.ts
1250
1285
  function getPortStreamMode(schema, portId) {
@@ -1348,6 +1383,42 @@ function hasStructuredOutput(schema) {
1348
1383
  }
1349
1384
 
1350
1385
  // src/task/TaskRunner.ts
1386
+ async function serializeOutputPorts(output, schema) {
1387
+ if (!schema?.properties)
1388
+ return output;
1389
+ const out = { ...output };
1390
+ for (const [key, prop] of Object.entries(schema.properties)) {
1391
+ const codec = prop.format ? getPortCodec(prop.format) : undefined;
1392
+ if (codec && out[key] !== undefined) {
1393
+ out[key] = await codec.serialize(out[key]);
1394
+ }
1395
+ }
1396
+ return out;
1397
+ }
1398
+ async function deserializeOutputPorts(output, schema) {
1399
+ if (!schema?.properties)
1400
+ return output;
1401
+ const out = { ...output };
1402
+ for (const [key, prop] of Object.entries(schema.properties)) {
1403
+ const codec = prop.format ? getPortCodec(prop.format) : undefined;
1404
+ if (codec && out[key] !== undefined) {
1405
+ out[key] = await codec.deserialize(out[key]);
1406
+ }
1407
+ }
1408
+ return out;
1409
+ }
1410
+ async function normalizeInputsForCacheKey(inputs, schema) {
1411
+ if (!schema?.properties)
1412
+ return inputs;
1413
+ const out = { ...inputs };
1414
+ for (const [key, prop] of Object.entries(schema.properties)) {
1415
+ const codec = prop.format ? getPortCodec(prop.format) : undefined;
1416
+ if (codec && out[key] !== undefined) {
1417
+ out[key] = await codec.serialize(out[key]);
1418
+ }
1419
+ }
1420
+ return out;
1421
+ }
1351
1422
  function hasRunConfig(i) {
1352
1423
  return i !== null && typeof i === "object" && "runConfig" in i;
1353
1424
  }
@@ -1364,6 +1435,7 @@ class TaskRunner {
1364
1435
  timeoutTimer;
1365
1436
  pendingTimeoutError;
1366
1437
  shouldAccumulate = true;
1438
+ runWithPreviews = false;
1367
1439
  telemetrySpan;
1368
1440
  constructor(task) {
1369
1441
  this.task = task;
@@ -1403,9 +1475,13 @@ class TaskRunner {
1403
1475
  getLogger().warn(`Task "${this.task.type}" declares streaming output (x-stream: "${streamMode}") ` + `but does not implement executeStream(). Falling back to non-streaming execute().`);
1404
1476
  }
1405
1477
  }
1478
+ const inputSchema = this.task.constructor.inputSchema();
1479
+ const outputSchema = this.task.constructor.outputSchema();
1480
+ const inputsForKey = this.outputCache ? await normalizeInputsForCacheKey(inputs, inputSchema) : inputs;
1406
1481
  if (this.task.cacheable) {
1407
- outputs = await this.outputCache?.getOutput(this.task.type, inputs);
1408
- if (outputs) {
1482
+ const cached = await this.outputCache?.getOutput(this.task.type, inputsForKey);
1483
+ if (cached !== undefined) {
1484
+ outputs = await deserializeOutputPorts(cached, outputSchema);
1409
1485
  this.telemetrySpan?.addEvent("workglow.task.cache_hit");
1410
1486
  if (isStreamable) {
1411
1487
  this.task.runOutputData = outputs;
@@ -1424,7 +1500,8 @@ class TaskRunner {
1424
1500
  outputs = await this.executeTask(inputs);
1425
1501
  }
1426
1502
  if (this.task.cacheable && outputs !== undefined) {
1427
- await this.outputCache?.saveOutput(this.task.type, inputs, outputs);
1503
+ const wireOutputs = await serializeOutputPorts(outputs, outputSchema);
1504
+ await this.outputCache?.saveOutput(this.task.type, inputsForKey, wireOutputs);
1428
1505
  }
1429
1506
  this.task.runOutputData = outputs ?? {};
1430
1507
  }
@@ -1641,6 +1718,7 @@ class TaskRunner {
1641
1718
  this.outputCache = cache;
1642
1719
  }
1643
1720
  this.shouldAccumulate = config.shouldAccumulate !== false;
1721
+ this.runWithPreviews = config.runWithPreviews === true;
1644
1722
  if (config.updateProgress) {
1645
1723
  this.updateProgress = config.updateProgress;
1646
1724
  }
@@ -2812,6 +2890,7 @@ class TaskGraphRunner {
2812
2890
  graph;
2813
2891
  outputCache;
2814
2892
  accumulateLeafOutputs = true;
2893
+ runWithPreviews = false;
2815
2894
  registry = globalServiceRegistry3;
2816
2895
  resourceScope;
2817
2896
  abortController;
@@ -3046,6 +3125,24 @@ class TaskGraphRunner {
3046
3125
  }
3047
3126
  async pushOutputFromNodeToEdges(node, results) {
3048
3127
  const dataflows = this.graph.getTargetDataflows(node.id);
3128
+ if (Object.keys(results).length > 0) {
3129
+ const consumerCounts = new Map;
3130
+ for (const dataflow of dataflows) {
3131
+ if (dataflow.stream !== undefined)
3132
+ continue;
3133
+ const port = dataflow.sourceTaskPortId;
3134
+ consumerCounts.set(port, (consumerCounts.get(port) ?? 0) + 1);
3135
+ }
3136
+ for (const [port, count] of consumerCounts) {
3137
+ const extra = this.runWithPreviews ? count : count - 1;
3138
+ if (extra <= 0)
3139
+ continue;
3140
+ const value = results[port];
3141
+ const ref = asRefcountable(value);
3142
+ if (ref)
3143
+ ref.retain(extra);
3144
+ }
3145
+ }
3049
3146
  for (const dataflow of dataflows) {
3050
3147
  if (dataflow.stream !== undefined)
3051
3148
  continue;
@@ -3215,7 +3312,8 @@ class TaskGraphRunner {
3215
3312
  outputCache: this.outputCache ?? false,
3216
3313
  updateProgress: async (task2, progress, message, ...args) => await this.handleProgress(task2, progress, message, ...args),
3217
3314
  registry: this.registry,
3218
- resourceScope: this.resourceScope
3315
+ resourceScope: this.resourceScope,
3316
+ runWithPreviews: this.runWithPreviews
3219
3317
  });
3220
3318
  await this.pushOutputFromNodeToEdges(task, results);
3221
3319
  return {
@@ -3265,7 +3363,8 @@ class TaskGraphRunner {
3265
3363
  shouldAccumulate,
3266
3364
  updateProgress: async (task2, progress, message, ...args) => await this.handleProgress(task2, progress, message, ...args),
3267
3365
  registry: this.registry,
3268
- resourceScope: this.resourceScope
3366
+ resourceScope: this.resourceScope,
3367
+ runWithPreviews: this.runWithPreviews
3269
3368
  });
3270
3369
  await this.pushOutputFromNodeToEdges(task, results);
3271
3370
  return {
@@ -3340,6 +3439,17 @@ class TaskGraphRunner {
3340
3439
  }
3341
3440
  }
3342
3441
  resetTask(graph, task, runId) {
3442
+ const previous = task.runOutputData;
3443
+ if (previous) {
3444
+ for (const port of Object.keys(previous)) {
3445
+ const ref = asRefcountable(previous[port]);
3446
+ if (!ref)
3447
+ continue;
3448
+ try {
3449
+ ref.release();
3450
+ } catch {}
3451
+ }
3452
+ }
3343
3453
  task.status = TaskStatus.PENDING;
3344
3454
  task.resetInputData();
3345
3455
  task.runOutputData = {};
@@ -3373,6 +3483,7 @@ class TaskGraphRunner {
3373
3483
  this.resourceScope = config.resourceScope;
3374
3484
  }
3375
3485
  this.accumulateLeafOutputs = config?.accumulateLeafOutputs !== false;
3486
+ this.runWithPreviews = config?.runWithPreviews === true;
3376
3487
  if (config?.outputCache !== undefined) {
3377
3488
  if (typeof config.outputCache === "boolean") {
3378
3489
  if (config.outputCache === true) {
@@ -3472,6 +3583,7 @@ class TaskGraphRunner {
3472
3583
  throw new TaskConfigurationError(`Graph has ${taskCount} tasks, exceeding the limit of ${config.maxTasks}`);
3473
3584
  }
3474
3585
  }
3586
+ this.runWithPreviews = false;
3475
3587
  this.previewScheduler.reset();
3476
3588
  this.previewRunning = true;
3477
3589
  }
@@ -3571,7 +3683,8 @@ class GraphAsTaskRunner extends TaskRunner {
3571
3683
  parentSignal: this.abortController?.signal,
3572
3684
  outputCache: this.outputCache,
3573
3685
  registry: this.registry,
3574
- resourceScope: this.resourceScope
3686
+ resourceScope: this.resourceScope,
3687
+ runWithPreviews: this.runWithPreviews
3575
3688
  });
3576
3689
  unsubscribe();
3577
3690
  return results;
@@ -4034,7 +4147,8 @@ class TaskGraph {
4034
4147
  registry: config?.registry,
4035
4148
  timeout: config?.timeout,
4036
4149
  maxTasks: config?.maxTasks,
4037
- resourceScope: config?.resourceScope
4150
+ resourceScope: config?.resourceScope,
4151
+ runWithPreviews: config?.runWithPreviews
4038
4152
  });
4039
4153
  }
4040
4154
  runPreview(input = {}, config = {}) {
@@ -4887,7 +5001,8 @@ class Workflow {
4887
5001
  parentSignal: this._abortController.signal,
4888
5002
  outputCache: this._outputCache,
4889
5003
  registry: config?.registry ?? this._registry,
4890
- resourceScope: config?.resourceScope
5004
+ resourceScope: config?.resourceScope,
5005
+ runWithPreviews: config?.runWithPreviews
4891
5006
  });
4892
5007
  const results = this.graph.mergeExecuteOutputsToRunOutput(output, PROPERTY_ARRAY);
4893
5008
  this.events.emit("complete");
@@ -8121,6 +8236,14 @@ class TaskOutputTabularRepository extends TaskOutputRepository {
8121
8236
  this.emit("output_pruned");
8122
8237
  }
8123
8238
  }
8239
+ // src/storage/PortCodecRegistry.ts
8240
+ import {
8241
+ registerPortCodec,
8242
+ getPortCodec as getPortCodec2,
8243
+ _resetPortCodecsForTests
8244
+ } from "@workglow/util";
8245
+ // src/node.ts
8246
+ registerRefcountablePredicate((v) => !!v && typeof v === "object" && ("backend" in v) && ("retain" in v) && ("release" in v) && ("materialize" in v));
8124
8247
  export {
8125
8248
  wrapSchemaInArray,
8126
8249
  whileTaskConfigSchema,
@@ -8143,6 +8266,8 @@ export {
8143
8266
  resolveIterationBound,
8144
8267
  resetMethodNameCache,
8145
8268
  removeIterationProperties,
8269
+ registerRefcountablePredicate,
8270
+ registerPortCodec,
8146
8271
  registerJobQueueFactory,
8147
8272
  registerBuiltInTransforms,
8148
8273
  registerBaseTasks,
@@ -8178,6 +8303,7 @@ export {
8178
8303
  getSchemaFormat,
8179
8304
  getProfileGrants,
8180
8305
  getPortStreamMode,
8306
+ getPortCodec2 as getPortCodec,
8181
8307
  getOutputStreamMode,
8182
8308
  getObjectSchema,
8183
8309
  getObjectPortId,
@@ -8224,9 +8350,12 @@ export {
8224
8350
  calculateNodeDepths,
8225
8351
  buildIterationInputSchema,
8226
8352
  autoConnect,
8353
+ asRefcountable,
8227
8354
  addIterationContextToSchema,
8228
8355
  addBoundaryNodesToGraphJson,
8229
8356
  addBoundaryNodesToDependencyJson,
8357
+ _resetRefcountablePredicatesForTests,
8358
+ _resetPortCodecsForTests,
8230
8359
  WorkflowError,
8231
8360
  Workflow,
8232
8361
  WhileTaskRunner,
@@ -8300,4 +8429,4 @@ export {
8300
8429
  BROWSER_GRANTS
8301
8430
  };
8302
8431
 
8303
- //# debugId=8744F550EEB96ECE64756E2164756E21
8432
+ //# debugId=1770AD648331E38064756E2164756E21