@workglow/task-graph 0.2.17 → 0.2.18

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/bun.js CHANGED
@@ -585,6 +585,10 @@ function computeGraphEntitlements(graph, options) {
585
585
  }
586
586
  // src/task/InputResolver.ts
587
587
  import { getInputResolvers } from "@workglow/util";
588
+ function isPlainObject(value) {
589
+ const proto = Object.getPrototypeOf(value);
590
+ return proto === Object.prototype || proto === null;
591
+ }
588
592
  function getSchemaFormat(schema, visited = new WeakSet) {
589
593
  if (typeof schema !== "object" || schema === null)
590
594
  return;
@@ -672,6 +676,7 @@ async function resolveSchemaInputs(input, schema, config, visited = new Set) {
672
676
  for (const [key, propSchema] of Object.entries(properties)) {
673
677
  let value = resolved[key];
674
678
  const format = getSchemaFormat(propSchema);
679
+ let phase1Transformed = false;
675
680
  if (format) {
676
681
  let resolver = resolvers.get(format);
677
682
  if (!resolver) {
@@ -682,14 +687,18 @@ async function resolveSchemaInputs(input, schema, config, visited = new Set) {
682
687
  if (typeof value === "string") {
683
688
  value = await resolver(value, format, config.registry);
684
689
  resolved[key] = value;
690
+ phase1Transformed = true;
685
691
  } else if (Array.isArray(value) && value.some((item) => typeof item === "string")) {
686
692
  const results = await Promise.all(value.map((item) => typeof item === "string" ? resolver(item, format, config.registry) : item));
687
693
  value = results.filter((result) => result !== undefined);
688
694
  resolved[key] = value;
695
+ phase1Transformed = true;
689
696
  }
690
697
  }
691
698
  }
692
- if (value !== null && value !== undefined && typeof value === "object" && !Array.isArray(value)) {
699
+ const hasFormatResolver = format ? !!(resolvers.get(format) ?? resolvers.get(getFormatPrefix(format))) : false;
700
+ const skipPhase2 = hasFormatResolver && !phase1Transformed;
701
+ if (!skipPhase2 && value !== null && value !== undefined && typeof value === "object" && !Array.isArray(value) && isPlainObject(value)) {
693
702
  const objectSchema = getObjectSchema(propSchema);
694
703
  if (objectSchema && !visited.has(objectSchema)) {
695
704
  visited.add(objectSchema);
@@ -1135,6 +1144,31 @@ import {
1135
1144
  uuid4 as uuid43
1136
1145
  } from "@workglow/util";
1137
1146
 
1147
+ // src/refcountable.ts
1148
+ var GLOBAL_KEY = Symbol.for("@workglow/task-graph/refcountable.predicates");
1149
+ var _g = globalThis;
1150
+ if (!Array.isArray(_g[GLOBAL_KEY])) {
1151
+ _g[GLOBAL_KEY] = [];
1152
+ }
1153
+ var predicates = _g[GLOBAL_KEY];
1154
+ function registerRefcountablePredicate(p) {
1155
+ predicates.push(p);
1156
+ }
1157
+ function asRefcountable(v) {
1158
+ if (v === null || v === undefined)
1159
+ return null;
1160
+ if (typeof v !== "object")
1161
+ return null;
1162
+ for (const p of predicates) {
1163
+ if (p(v))
1164
+ return v;
1165
+ }
1166
+ return null;
1167
+ }
1168
+ function _resetRefcountablePredicatesForTests() {
1169
+ predicates.length = 0;
1170
+ }
1171
+
1138
1172
  // src/storage/TaskOutputRepository.ts
1139
1173
  import { createServiceToken as createServiceToken2, EventEmitter as EventEmitter2 } from "@workglow/util";
1140
1174
  var TASK_OUTPUT_REPOSITORY = createServiceToken2("taskgraph.taskOutputRepository");
@@ -1246,6 +1280,7 @@ import {
1246
1280
  globalServiceRegistry as globalServiceRegistry2,
1247
1281
  SpanStatusCode
1248
1282
  } from "@workglow/util";
1283
+ import { getPortCodec } from "@workglow/util";
1249
1284
 
1250
1285
  // src/task/StreamTypes.ts
1251
1286
  function getPortStreamMode(schema, portId) {
@@ -1349,6 +1384,42 @@ function hasStructuredOutput(schema) {
1349
1384
  }
1350
1385
 
1351
1386
  // src/task/TaskRunner.ts
1387
+ async function serializeOutputPorts(output, schema) {
1388
+ if (!schema?.properties)
1389
+ return output;
1390
+ const out = { ...output };
1391
+ for (const [key, prop] of Object.entries(schema.properties)) {
1392
+ const codec = prop.format ? getPortCodec(prop.format) : undefined;
1393
+ if (codec && out[key] !== undefined) {
1394
+ out[key] = await codec.serialize(out[key]);
1395
+ }
1396
+ }
1397
+ return out;
1398
+ }
1399
+ async function deserializeOutputPorts(output, schema) {
1400
+ if (!schema?.properties)
1401
+ return output;
1402
+ const out = { ...output };
1403
+ for (const [key, prop] of Object.entries(schema.properties)) {
1404
+ const codec = prop.format ? getPortCodec(prop.format) : undefined;
1405
+ if (codec && out[key] !== undefined) {
1406
+ out[key] = await codec.deserialize(out[key]);
1407
+ }
1408
+ }
1409
+ return out;
1410
+ }
1411
+ async function normalizeInputsForCacheKey(inputs, schema) {
1412
+ if (!schema?.properties)
1413
+ return inputs;
1414
+ const out = { ...inputs };
1415
+ for (const [key, prop] of Object.entries(schema.properties)) {
1416
+ const codec = prop.format ? getPortCodec(prop.format) : undefined;
1417
+ if (codec && out[key] !== undefined) {
1418
+ out[key] = await codec.serialize(out[key]);
1419
+ }
1420
+ }
1421
+ return out;
1422
+ }
1352
1423
  function hasRunConfig(i) {
1353
1424
  return i !== null && typeof i === "object" && "runConfig" in i;
1354
1425
  }
@@ -1404,9 +1475,13 @@ class TaskRunner {
1404
1475
  getLogger().warn(`Task "${this.task.type}" declares streaming output (x-stream: "${streamMode}") ` + `but does not implement executeStream(). Falling back to non-streaming execute().`);
1405
1476
  }
1406
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;
1407
1481
  if (this.task.cacheable) {
1408
- outputs = await this.outputCache?.getOutput(this.task.type, inputs);
1409
- if (outputs) {
1482
+ const cached = await this.outputCache?.getOutput(this.task.type, inputsForKey);
1483
+ if (cached !== undefined) {
1484
+ outputs = await deserializeOutputPorts(cached, outputSchema);
1410
1485
  this.telemetrySpan?.addEvent("workglow.task.cache_hit");
1411
1486
  if (isStreamable) {
1412
1487
  this.task.runOutputData = outputs;
@@ -1425,7 +1500,8 @@ class TaskRunner {
1425
1500
  outputs = await this.executeTask(inputs);
1426
1501
  }
1427
1502
  if (this.task.cacheable && outputs !== undefined) {
1428
- 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);
1429
1505
  }
1430
1506
  this.task.runOutputData = outputs ?? {};
1431
1507
  }
@@ -3047,6 +3123,23 @@ class TaskGraphRunner {
3047
3123
  }
3048
3124
  async pushOutputFromNodeToEdges(node, results) {
3049
3125
  const dataflows = this.graph.getTargetDataflows(node.id);
3126
+ if (Object.keys(results).length > 0) {
3127
+ const consumerCounts = new Map;
3128
+ for (const dataflow of dataflows) {
3129
+ if (dataflow.stream !== undefined)
3130
+ continue;
3131
+ const port = dataflow.sourceTaskPortId;
3132
+ consumerCounts.set(port, (consumerCounts.get(port) ?? 0) + 1);
3133
+ }
3134
+ for (const [port, count] of consumerCounts) {
3135
+ if (count <= 1)
3136
+ continue;
3137
+ const value = results[port];
3138
+ const ref = asRefcountable(value);
3139
+ if (ref)
3140
+ ref.retain(count - 1);
3141
+ }
3142
+ }
3050
3143
  for (const dataflow of dataflows) {
3051
3144
  if (dataflow.stream !== undefined)
3052
3145
  continue;
@@ -8122,6 +8215,14 @@ class TaskOutputTabularRepository extends TaskOutputRepository {
8122
8215
  this.emit("output_pruned");
8123
8216
  }
8124
8217
  }
8218
+ // src/storage/PortCodecRegistry.ts
8219
+ import {
8220
+ registerPortCodec,
8221
+ getPortCodec as getPortCodec2,
8222
+ _resetPortCodecsForTests
8223
+ } from "@workglow/util";
8224
+ // src/bun.ts
8225
+ registerRefcountablePredicate((v) => !!v && typeof v === "object" && ("backend" in v) && ("retain" in v) && ("release" in v) && ("materialize" in v));
8125
8226
  export {
8126
8227
  wrapSchemaInArray,
8127
8228
  whileTaskConfigSchema,
@@ -8144,6 +8245,8 @@ export {
8144
8245
  resolveIterationBound,
8145
8246
  resetMethodNameCache,
8146
8247
  removeIterationProperties,
8248
+ registerRefcountablePredicate,
8249
+ registerPortCodec,
8147
8250
  registerJobQueueFactory,
8148
8251
  registerBuiltInTransforms,
8149
8252
  registerBaseTasks,
@@ -8179,6 +8282,7 @@ export {
8179
8282
  getSchemaFormat,
8180
8283
  getProfileGrants,
8181
8284
  getPortStreamMode,
8285
+ getPortCodec2 as getPortCodec,
8182
8286
  getOutputStreamMode,
8183
8287
  getObjectSchema,
8184
8288
  getObjectPortId,
@@ -8225,9 +8329,12 @@ export {
8225
8329
  calculateNodeDepths,
8226
8330
  buildIterationInputSchema,
8227
8331
  autoConnect,
8332
+ asRefcountable,
8228
8333
  addIterationContextToSchema,
8229
8334
  addBoundaryNodesToGraphJson,
8230
8335
  addBoundaryNodesToDependencyJson,
8336
+ _resetRefcountablePredicatesForTests,
8337
+ _resetPortCodecsForTests,
8231
8338
  WorkflowError,
8232
8339
  Workflow,
8233
8340
  WhileTaskRunner,
@@ -8301,4 +8408,4 @@ export {
8301
8408
  BROWSER_GRANTS
8302
8409
  };
8303
8410
 
8304
- //# debugId=6F0C663FBE6F199E64756E2164756E21
8411
+ //# debugId=791136A32061C4D664756E2164756E21