@cadenza.io/core 3.24.0 → 3.25.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.mjs CHANGED
@@ -2636,7 +2636,8 @@ var GraphNode = class _GraphNode extends SignalEmitter {
2636
2636
  if (!this.divided && !this.processing) {
2637
2637
  this.processing = true;
2638
2638
  const inputValidation = this.task.validateInput(
2639
- this.isMeta() ? this.context.getMetadata() : this.context.getContext()
2639
+ this.isMeta() ? this.context.getFullContext() : this.context.getContext(),
2640
+ this.context.getMetadata()
2640
2641
  );
2641
2642
  if (inputValidation !== true) {
2642
2643
  this.onError(inputValidation.__validationErrors);
@@ -2729,7 +2730,7 @@ var GraphNode = class _GraphNode extends SignalEmitter {
2729
2730
  }
2730
2731
  }
2731
2732
  inquire(inquiry, context, options) {
2732
- return Cadenza.inquire(
2733
+ return Cadenza.resolveRuntimeInquiryDelegate()(
2733
2734
  inquiry,
2734
2735
  { ...context, __executionTraceId: this.executionTraceId },
2735
2736
  options
@@ -2971,7 +2972,10 @@ var GraphNode = class _GraphNode extends SignalEmitter {
2971
2972
  return this.divideAsync(current);
2972
2973
  }
2973
2974
  while (!current.done && current.value !== void 0) {
2974
- const outputValidation = this.task.validateOutput(current.value);
2975
+ const outputValidation = this.task.validateOutput(
2976
+ current.value,
2977
+ this.context.getMetadata()
2978
+ );
2975
2979
  if (outputValidation !== true) {
2976
2980
  this.onError(outputValidation.__validationErrors);
2977
2981
  break;
@@ -2983,7 +2987,10 @@ var GraphNode = class _GraphNode extends SignalEmitter {
2983
2987
  } else if (this.result !== void 0 && !this.errored) {
2984
2988
  newNodes.push(...this.generateNewNodes(this.result));
2985
2989
  if (typeof this.result !== "boolean") {
2986
- const outputValidation = this.task.validateOutput(this.result);
2990
+ const outputValidation = this.task.validateOutput(
2991
+ this.result,
2992
+ this.context.getMetadata()
2993
+ );
2987
2994
  if (outputValidation !== true) {
2988
2995
  this.onError(outputValidation.__validationErrors);
2989
2996
  }
@@ -3015,7 +3022,10 @@ var GraphNode = class _GraphNode extends SignalEmitter {
3015
3022
  async divideAsync(current) {
3016
3023
  const nextNodes = [];
3017
3024
  const _current = await current;
3018
- const outputValidation = this.task.validateOutput(_current.value);
3025
+ const outputValidation = this.task.validateOutput(
3026
+ _current.value,
3027
+ this.context.getMetadata()
3028
+ );
3019
3029
  if (outputValidation !== true) {
3020
3030
  this.onError(outputValidation.__validationErrors);
3021
3031
  return nextNodes;
@@ -3023,7 +3033,10 @@ var GraphNode = class _GraphNode extends SignalEmitter {
3023
3033
  nextNodes.push(...this.generateNewNodes(_current.value));
3024
3034
  }
3025
3035
  for await (const result of this.result) {
3026
- const outputValidation2 = this.task.validateOutput(result);
3036
+ const outputValidation2 = this.task.validateOutput(
3037
+ result,
3038
+ this.context.getMetadata()
3039
+ );
3027
3040
  if (outputValidation2 !== true) {
3028
3041
  this.onError(outputValidation2.__validationErrors);
3029
3042
  return [];
@@ -3470,6 +3483,11 @@ var GraphRunner = class extends SignalEmitter {
3470
3483
  context.__executionTraceId = executionTraceId;
3471
3484
  const routineExecId = context.__routineExecId ?? uuid5();
3472
3485
  context.__routineExecId = routineExecId;
3486
+ Cadenza.applyRuntimeValidationScopesToContext(
3487
+ context,
3488
+ routineName,
3489
+ allTasks
3490
+ );
3473
3491
  const ctx = new GraphContext(context || {});
3474
3492
  if (!isSubMeta) {
3475
3493
  if (isNewTrace) {
@@ -4283,7 +4301,7 @@ var Task = class _Task extends SignalEmitter {
4283
4301
  * @param {number} [retryDelayMax=0] - The maximum delay (in milliseconds) allowed between retries.
4284
4302
  * @param {number} [retryDelayFactor=1] - The factor by which the retry delay increases after each attempt.
4285
4303
  */
4286
- constructor(name, task, description = "", concurrency = 0, timeout = 0, register = true, isUnique = false, isMeta = false, isSubMeta = false, isHidden = false, getTagCallback = void 0, inputSchema = { type: "object" }, validateInputContext = false, outputSchema = { type: "object" }, validateOutputContext = false, retryCount = 0, retryDelay = 0, retryDelayMax = 0, retryDelayFactor = 1) {
4304
+ constructor(name, task, description = "", concurrency = 0, timeout = 0, register = true, isUnique = false, isMeta = false, isSubMeta = false, isHidden = false, getTagCallback = void 0, inputSchema, validateInputContext = false, outputSchema, validateOutputContext = false, retryCount = 0, retryDelay = 0, retryDelayMax = 0, retryDelayFactor = 1) {
4287
4305
  super(isSubMeta || isHidden);
4288
4306
  this.version = 1;
4289
4307
  this.isMeta = false;
@@ -4296,8 +4314,10 @@ var Task = class _Task extends SignalEmitter {
4296
4314
  this.isEphemeral = false;
4297
4315
  this.isDebounce = false;
4298
4316
  this.inputContextSchema = { type: "object" };
4317
+ this.hasExplicitInputContextSchema = false;
4299
4318
  this.validateInputContext = false;
4300
4319
  this.outputContextSchema = { type: "object" };
4320
+ this.hasExplicitOutputContextSchema = false;
4301
4321
  this.validateOutputContext = false;
4302
4322
  this.retryCount = 0;
4303
4323
  this.retryDelay = 0;
@@ -4327,9 +4347,11 @@ var Task = class _Task extends SignalEmitter {
4327
4347
  this.isMeta = isMeta;
4328
4348
  this.isSubMeta = isSubMeta;
4329
4349
  this.isHidden = isHidden;
4330
- this.inputContextSchema = inputSchema;
4350
+ this.inputContextSchema = inputSchema ?? { type: "object" };
4351
+ this.hasExplicitInputContextSchema = inputSchema !== void 0;
4331
4352
  this.validateInputContext = validateInputContext;
4332
- this.outputContextSchema = outputSchema;
4353
+ this.outputContextSchema = outputSchema ?? { type: "object" };
4354
+ this.hasExplicitOutputContextSchema = outputSchema !== void 0;
4333
4355
  this.validateOutputContext = validateOutputContext;
4334
4356
  this.retryCount = retryCount;
4335
4357
  this.retryDelay = retryDelay;
@@ -4346,6 +4368,8 @@ var Task = class _Task extends SignalEmitter {
4346
4368
  "meta.task.destroyed",
4347
4369
  "meta.task.output_validation_failed",
4348
4370
  "meta.task.input_validation_failed",
4371
+ "meta.task.input_schema_missing",
4372
+ "meta.task.output_schema_missing",
4349
4373
  "meta.task.relationship_added",
4350
4374
  "meta.task.relationship_removed",
4351
4375
  "meta.task.layer_index_changed",
@@ -4434,9 +4458,9 @@ var Task = class _Task extends SignalEmitter {
4434
4458
  this.isSubMeta,
4435
4459
  this.isHidden,
4436
4460
  this.getTag,
4437
- this.inputContextSchema,
4461
+ this.hasExplicitInputContextSchema ? this.inputContextSchema : void 0,
4438
4462
  this.validateInputContext,
4439
- this.outputContextSchema,
4463
+ this.hasExplicitOutputContextSchema ? this.outputContextSchema : void 0,
4440
4464
  this.validateOutputContext,
4441
4465
  this.retryCount,
4442
4466
  this.retryDelay,
@@ -4483,9 +4507,11 @@ var Task = class _Task extends SignalEmitter {
4483
4507
  }
4484
4508
  setInputContextSchema(schema) {
4485
4509
  this.inputContextSchema = schema;
4510
+ this.hasExplicitInputContextSchema = true;
4486
4511
  }
4487
4512
  setOutputContextSchema(schema) {
4488
4513
  this.outputContextSchema = schema;
4514
+ this.hasExplicitOutputContextSchema = true;
4489
4515
  }
4490
4516
  setValidateInputContext(value) {
4491
4517
  this.validateInputContext = value;
@@ -4722,19 +4748,86 @@ var Task = class _Task extends SignalEmitter {
4722
4748
  * @param {AnyObject} context - The input context to validate.
4723
4749
  * @return {true | AnyObject} - Returns `true` if validation succeeds, otherwise returns an error object containing details of the validation failure.
4724
4750
  */
4725
- validateInput(context) {
4726
- if (this.validateInputContext) {
4727
- const validationResult = this.validateSchema(
4728
- context,
4729
- this.inputContextSchema
4730
- );
4731
- if (!validationResult.valid) {
4732
- this.emitWithMetadata("meta.task.input_validation_failed", {
4733
- __taskName: this.name,
4734
- __taskVersion: this.version,
4735
- __context: context,
4736
- __errors: validationResult.errors
4737
- });
4751
+ getEffectiveValidationMode(direction, metadata = {}) {
4752
+ const resolvedPolicy = Cadenza.resolveRuntimeValidationPolicyForTask(
4753
+ this,
4754
+ metadata
4755
+ );
4756
+ const policyMode = direction === "input" ? resolvedPolicy.inputMode : resolvedPolicy.outputMode;
4757
+ const isExplicit = direction === "input" ? this.validateInputContext : this.validateOutputContext;
4758
+ return {
4759
+ resolvedPolicy,
4760
+ mode: isExplicit ? "enforce" : policyMode,
4761
+ warnOnMissingSchema: direction === "input" ? resolvedPolicy.warnOnMissingInputSchema : resolvedPolicy.warnOnMissingOutputSchema,
4762
+ hasExplicitSchema: direction === "input" ? this.hasExplicitInputContextSchema : this.hasExplicitOutputContextSchema,
4763
+ schema: direction === "input" ? this.inputContextSchema : this.outputContextSchema
4764
+ };
4765
+ }
4766
+ warnMissingSchema(direction, metadata = {}) {
4767
+ const resolvedPolicy = Cadenza.resolveRuntimeValidationPolicyForTask(
4768
+ this,
4769
+ metadata
4770
+ );
4771
+ const cacheKey = `${this.name}:${this.version}:${direction}:${resolvedPolicy.layer}`;
4772
+ if (!Cadenza.shouldEmitMissingSchemaWarning(cacheKey)) {
4773
+ return;
4774
+ }
4775
+ const ctx = {
4776
+ __taskName: this.name,
4777
+ __taskVersion: this.version,
4778
+ __layer: resolvedPolicy.layer,
4779
+ __activeScopeIds: resolvedPolicy.activeScopeIds
4780
+ };
4781
+ this.emitWithMetadata(`meta.task.${direction}_schema_missing`, ctx);
4782
+ console.warn(
4783
+ `[CADENZA_VALIDATION] Missing ${direction} schema for task '${this.name}'`,
4784
+ {
4785
+ taskName: this.name,
4786
+ taskVersion: this.version,
4787
+ direction,
4788
+ layer: resolvedPolicy.layer,
4789
+ activeScopeIds: resolvedPolicy.activeScopeIds
4790
+ }
4791
+ );
4792
+ }
4793
+ logValidationFailure(direction, validationErrors, metadata = {}) {
4794
+ const resolvedPolicy = Cadenza.resolveRuntimeValidationPolicyForTask(
4795
+ this,
4796
+ metadata
4797
+ );
4798
+ console.error(
4799
+ `[CADENZA_VALIDATION] ${direction} validation failed for task '${this.name}'`,
4800
+ {
4801
+ taskName: this.name,
4802
+ taskVersion: this.version,
4803
+ direction,
4804
+ layer: resolvedPolicy.layer,
4805
+ activeScopeIds: resolvedPolicy.activeScopeIds,
4806
+ errors: validationErrors
4807
+ }
4808
+ );
4809
+ }
4810
+ validateInput(context, metadata = {}) {
4811
+ const config = this.getEffectiveValidationMode("input", metadata);
4812
+ if (config.mode === "off") {
4813
+ return true;
4814
+ }
4815
+ if (!config.hasExplicitSchema) {
4816
+ if (config.warnOnMissingSchema) {
4817
+ this.warnMissingSchema("input", metadata);
4818
+ }
4819
+ return true;
4820
+ }
4821
+ const validationResult = this.validateSchema(context, config.schema);
4822
+ if (!validationResult.valid) {
4823
+ this.emitWithMetadata("meta.task.input_validation_failed", {
4824
+ __taskName: this.name,
4825
+ __taskVersion: this.version,
4826
+ __context: context,
4827
+ __errors: validationResult.errors
4828
+ });
4829
+ this.logValidationFailure("input", validationResult.errors, metadata);
4830
+ if (config.mode === "enforce") {
4738
4831
  return {
4739
4832
  errored: true,
4740
4833
  __error: "Input context validation failed",
@@ -4751,19 +4844,27 @@ var Task = class _Task extends SignalEmitter {
4751
4844
  * @return {true | AnyObject} Returns `true` if the output context is valid; otherwise, returns an object
4752
4845
  * containing error information when validation fails.
4753
4846
  */
4754
- validateOutput(context) {
4755
- if (this.validateOutputContext) {
4756
- const validationResult = this.validateSchema(
4757
- context,
4758
- this.outputContextSchema
4759
- );
4760
- if (!validationResult.valid) {
4761
- this.emitWithMetadata("meta.task.output_validation_failed", {
4762
- __taskName: this.name,
4763
- __taskVersion: this.version,
4764
- __result: context,
4765
- __errors: validationResult.errors
4766
- });
4847
+ validateOutput(context, metadata = {}) {
4848
+ const config = this.getEffectiveValidationMode("output", metadata);
4849
+ if (config.mode === "off") {
4850
+ return true;
4851
+ }
4852
+ if (!config.hasExplicitSchema) {
4853
+ if (config.warnOnMissingSchema) {
4854
+ this.warnMissingSchema("output", metadata);
4855
+ }
4856
+ return true;
4857
+ }
4858
+ const validationResult = this.validateSchema(context, config.schema);
4859
+ if (!validationResult.valid) {
4860
+ this.emitWithMetadata("meta.task.output_validation_failed", {
4861
+ __taskName: this.name,
4862
+ __taskVersion: this.version,
4863
+ __result: context,
4864
+ __errors: validationResult.errors
4865
+ });
4866
+ this.logValidationFailure("output", validationResult.errors, metadata);
4867
+ if (config.mode === "enforce") {
4767
4868
  return {
4768
4869
  errored: true,
4769
4870
  __error: "Output context validation failed",
@@ -5154,6 +5255,7 @@ var Task = class _Task extends SignalEmitter {
5154
5255
  intentName,
5155
5256
  intent.input
5156
5257
  );
5258
+ this.hasExplicitInputContextSchema = true;
5157
5259
  }
5158
5260
  if (intent?.output) {
5159
5261
  this.outputContextSchema = this.mergeSchemaVariant(
@@ -5161,6 +5263,7 @@ var Task = class _Task extends SignalEmitter {
5161
5263
  intentName,
5162
5264
  intent.output
5163
5265
  );
5266
+ this.hasExplicitOutputContextSchema = true;
5164
5267
  }
5165
5268
  }
5166
5269
  return this;
@@ -6864,6 +6967,146 @@ var Cadenza = class {
6864
6967
  static async inquire(inquiry, context, options) {
6865
6968
  return this.inquiryBroker?.inquire(inquiry, context, options);
6866
6969
  }
6970
+ static setRuntimeInquiryDelegate(delegate) {
6971
+ this.runtimeInquiryDelegate = delegate;
6972
+ }
6973
+ static resolveRuntimeInquiryDelegate() {
6974
+ return this.runtimeInquiryDelegate ?? ((inquiry, context, options) => this.inquire(inquiry, context, options));
6975
+ }
6976
+ static getRuntimeValidationPolicy() {
6977
+ return { ...this.runtimeValidationPolicy };
6978
+ }
6979
+ static setRuntimeValidationPolicy(policy = {}) {
6980
+ this.runtimeValidationPolicy = {
6981
+ ...this.runtimeValidationPolicy,
6982
+ ...policy
6983
+ };
6984
+ this.emittedMissingSchemaWarnings.clear();
6985
+ return this.getRuntimeValidationPolicy();
6986
+ }
6987
+ static replaceRuntimeValidationPolicy(policy = {}) {
6988
+ this.runtimeValidationPolicy = { ...policy };
6989
+ this.emittedMissingSchemaWarnings.clear();
6990
+ return this.getRuntimeValidationPolicy();
6991
+ }
6992
+ static clearRuntimeValidationPolicy() {
6993
+ this.runtimeValidationPolicy = {};
6994
+ this.emittedMissingSchemaWarnings.clear();
6995
+ }
6996
+ static getRuntimeValidationScopes() {
6997
+ return Array.from(this.runtimeValidationScopes.values()).map((scope) => ({
6998
+ ...scope,
6999
+ startTaskNames: scope.startTaskNames ? [...scope.startTaskNames] : void 0,
7000
+ startRoutineNames: scope.startRoutineNames ? [...scope.startRoutineNames] : void 0,
7001
+ policy: scope.policy ? { ...scope.policy } : void 0
7002
+ }));
7003
+ }
7004
+ static upsertRuntimeValidationScope(scope) {
7005
+ if (!scope.id?.trim()) {
7006
+ throw new Error("Runtime validation scope id is required");
7007
+ }
7008
+ const normalizedScope = {
7009
+ id: scope.id,
7010
+ active: scope.active !== false,
7011
+ startTaskNames: scope.startTaskNames ? [...new Set(scope.startTaskNames)] : void 0,
7012
+ startRoutineNames: scope.startRoutineNames ? [...new Set(scope.startRoutineNames)] : void 0,
7013
+ policy: scope.policy ? { ...scope.policy } : void 0
7014
+ };
7015
+ this.runtimeValidationScopes.set(scope.id, normalizedScope);
7016
+ this.emittedMissingSchemaWarnings.clear();
7017
+ return {
7018
+ ...normalizedScope,
7019
+ startTaskNames: normalizedScope.startTaskNames ? [...normalizedScope.startTaskNames] : void 0,
7020
+ startRoutineNames: normalizedScope.startRoutineNames ? [...normalizedScope.startRoutineNames] : void 0,
7021
+ policy: normalizedScope.policy ? { ...normalizedScope.policy } : void 0
7022
+ };
7023
+ }
7024
+ static removeRuntimeValidationScope(id) {
7025
+ this.runtimeValidationScopes.delete(id);
7026
+ this.emittedMissingSchemaWarnings.clear();
7027
+ }
7028
+ static clearRuntimeValidationScopes() {
7029
+ this.runtimeValidationScopes.clear();
7030
+ this.emittedMissingSchemaWarnings.clear();
7031
+ }
7032
+ static applyRuntimeValidationScopesToContext(context, routineName, tasks) {
7033
+ const existingScopeIds = /* @__PURE__ */ new Set();
7034
+ const metadataScopeIds = context.__metadata?.__runtimeValidationScopeIds;
7035
+ const rootScopeIds = context.__runtimeValidationScopeIds;
7036
+ if (Array.isArray(rootScopeIds)) {
7037
+ rootScopeIds.forEach((id) => existingScopeIds.add(id));
7038
+ }
7039
+ if (Array.isArray(metadataScopeIds)) {
7040
+ metadataScopeIds.forEach((id) => existingScopeIds.add(id));
7041
+ }
7042
+ const taskNames = new Set(tasks.map((task) => task.name));
7043
+ for (const scope of this.runtimeValidationScopes.values()) {
7044
+ if (scope.active === false) {
7045
+ continue;
7046
+ }
7047
+ const matchesRoutine = scope.startRoutineNames?.includes(routineName) === true;
7048
+ const matchesTask = scope.startTaskNames?.some((taskName) => taskNames.has(taskName)) === true;
7049
+ if (matchesRoutine || matchesTask) {
7050
+ existingScopeIds.add(scope.id);
7051
+ }
7052
+ }
7053
+ if (existingScopeIds.size > 0) {
7054
+ const scopeIds = Array.from(existingScopeIds);
7055
+ context.__runtimeValidationScopeIds = scopeIds;
7056
+ context.__metadata = {
7057
+ ...context.__metadata ?? {},
7058
+ __runtimeValidationScopeIds: scopeIds
7059
+ };
7060
+ }
7061
+ return context;
7062
+ }
7063
+ static resolveRuntimeValidationPolicyForTask(task, metadata = {}) {
7064
+ const layer = task.isMeta || task.isSubMeta || metadata.__isSubMeta ? "meta" : "business";
7065
+ const activeScopeIds = /* @__PURE__ */ new Set();
7066
+ const rootScopeIds = metadata.__runtimeValidationScopeIds;
7067
+ const nestedScopeIds = metadata.__metadata?.__runtimeValidationScopeIds;
7068
+ if (Array.isArray(rootScopeIds)) {
7069
+ rootScopeIds.forEach((id) => activeScopeIds.add(id));
7070
+ }
7071
+ if (Array.isArray(nestedScopeIds)) {
7072
+ nestedScopeIds.forEach((id) => activeScopeIds.add(id));
7073
+ }
7074
+ const mergedPolicy = {
7075
+ ...this.runtimeValidationPolicy
7076
+ };
7077
+ for (const scopeId of activeScopeIds) {
7078
+ const scope = this.runtimeValidationScopes.get(scopeId);
7079
+ if (!scope?.policy || scope.active === false) {
7080
+ continue;
7081
+ }
7082
+ Object.assign(mergedPolicy, scope.policy);
7083
+ }
7084
+ if (layer === "meta") {
7085
+ return {
7086
+ layer,
7087
+ inputMode: mergedPolicy.metaInput ?? "off",
7088
+ outputMode: mergedPolicy.metaOutput ?? "off",
7089
+ warnOnMissingInputSchema: mergedPolicy.warnOnMissingMetaInputSchema === true,
7090
+ warnOnMissingOutputSchema: mergedPolicy.warnOnMissingMetaOutputSchema === true,
7091
+ activeScopeIds: Array.from(activeScopeIds)
7092
+ };
7093
+ }
7094
+ return {
7095
+ layer,
7096
+ inputMode: mergedPolicy.businessInput ?? "off",
7097
+ outputMode: mergedPolicy.businessOutput ?? "off",
7098
+ warnOnMissingInputSchema: mergedPolicy.warnOnMissingBusinessInputSchema === true,
7099
+ warnOnMissingOutputSchema: mergedPolicy.warnOnMissingBusinessOutputSchema === true,
7100
+ activeScopeIds: Array.from(activeScopeIds)
7101
+ };
7102
+ }
7103
+ static shouldEmitMissingSchemaWarning(cacheKey) {
7104
+ if (this.emittedMissingSchemaWarnings.has(cacheKey)) {
7105
+ return false;
7106
+ }
7107
+ this.emittedMissingSchemaWarnings.add(cacheKey);
7108
+ return true;
7109
+ }
6867
7110
  /**
6868
7111
  * Creates an in-memory actor runtime instance.
6869
7112
  *
@@ -7463,11 +7706,18 @@ var Cadenza = class {
7463
7706
  this.registry?.reset();
7464
7707
  this.taskCache.clear();
7465
7708
  this.actorCache.clear();
7709
+ this.runtimeInquiryDelegate = void 0;
7710
+ this.runtimeValidationPolicy = {};
7711
+ this.runtimeValidationScopes.clear();
7712
+ this.emittedMissingSchemaWarnings.clear();
7466
7713
  this.isBootstrapped = false;
7467
7714
  }
7468
7715
  };
7469
7716
  Cadenza.taskCache = /* @__PURE__ */ new Map();
7470
7717
  Cadenza.actorCache = /* @__PURE__ */ new Map();
7718
+ Cadenza.runtimeValidationPolicy = {};
7719
+ Cadenza.runtimeValidationScopes = /* @__PURE__ */ new Map();
7720
+ Cadenza.emittedMissingSchemaWarnings = /* @__PURE__ */ new Set();
7471
7721
  Cadenza.isBootstrapped = false;
7472
7722
  Cadenza.mode = "production";
7473
7723