@ductape/sdk 0.1.145 → 0.1.148

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.
@@ -118,6 +118,8 @@ function formatErrorDetails(error) {
118
118
  const out = { message };
119
119
  if (err === null || err === void 0 ? void 0 : err.stack)
120
120
  out.stack = err.stack;
121
+ if ((err === null || err === void 0 ? void 0 : err.details) != null)
122
+ out.details = sanitizeForLog(err.details);
121
123
  if (err === null || err === void 0 ? void 0 : err.response) {
122
124
  out.status = (_b = err.response) === null || _b === void 0 ? void 0 : _b.status;
123
125
  const data = (_c = err.response) === null || _c === void 0 ? void 0 : _c.data;
@@ -165,6 +167,8 @@ class FeatureExecutor {
165
167
  this.functionInvocations = new Map();
166
168
  /** Step telemetry is accumulated and persisted with the terminal feature record in one round trip. */
167
169
  this.pendingProcessorResults = [];
170
+ this.assetSpans = [];
171
+ this.stepContexts = new Map();
168
172
  debugLog('[FeatureExecutor] constructor ENTRY', {
169
173
  feature_tag: feature.tag,
170
174
  product: options.product,
@@ -420,8 +424,18 @@ class FeatureExecutor {
420
424
  const inputStr = stringifyProcessorValue(inputPayload);
421
425
  const encKey = this.getProcessorResultEncryptionKey();
422
426
  const processorResult = Object.assign(Object.assign({}, (0, context_1.executionContextFields)()), { process_id: this.state.feature_id, product_id: this.productId || null, env: this.state.env, component: types_1.LogEventTypes.FEATURE, status, start: this.state.started_at, end: Date.now(), retryable: true, result: encKey ? (0, processor_utils_1.encrypt)(resultStr, encKey) : resultStr, input: encKey ? (0, processor_utils_1.encrypt)(inputStr, encKey) : inputStr, feature_id: this.state.feature_id, feature_tag: this.state.feature_tag, product_tag: this.state.product, workspace_id: this.config.workspace_id });
427
+ const assetResults = this.assetSpans.splice(0).map((span) => {
428
+ const spanResult = stringifyProcessorValue({
429
+ asset_type: span.asset_type,
430
+ asset_tag: span.asset_tag,
431
+ operation: span.asset_operation,
432
+ action: span.asset_action,
433
+ });
434
+ const spanInput = stringifyProcessorValue({});
435
+ return Object.assign(Object.assign({}, span), { process_id: span.span_id, product_id: this.productId || null, product_tag: this.state.product, workspace_id: this.config.workspace_id, env: this.state.env, component: 'asset_invocation', execution_kind: 'asset', retryable: true, result: encKey ? (0, processor_utils_1.encrypt)(spanResult, encKey) : spanResult, input: encKey ? (0, processor_utils_1.encrypt)(spanInput, encKey) : spanInput, asset_duration_ms: span.duration_ms, asset_error: span.error_message });
436
+ });
423
437
  this.trace('execution.persistence.sent', { status, payload: resultData });
424
- await this.processorApiService.saveResultsBatch([...this.pendingProcessorResults.splice(0), processorResult], this.getAuthPayload());
438
+ await this.processorApiService.saveResultsBatch([...this.pendingProcessorResults.splice(0), ...assetResults, processorResult], this.getAuthPayload());
425
439
  this.trace('execution.persistence.acknowledged', { status, process_id: this.state.feature_id });
426
440
  debugLog('[FeatureExecutor] persistExecutionResult SUCCESS', { feature_id: this.state.feature_id, status });
427
441
  }
@@ -457,8 +471,8 @@ class FeatureExecutor {
457
471
  * Persist individual step execution to backend (input/output per step in processor result).
458
472
  * Processor results for steps always have component: 'feature_step' and step_type set to the step kind.
459
473
  */
460
- async persistStepResult(step, status, output, error, duration, input) {
461
- var _a;
474
+ async persistStepResult(step, status, output, error, duration, input, errorDetails) {
475
+ var _a, _b;
462
476
  const resolvedInput = input !== null && input !== void 0 ? input : step.input;
463
477
  const stepType = this.getStepTypeForResult(step);
464
478
  debugLog('[FeatureExecutor] persistStepResult ENTRY', {
@@ -475,12 +489,12 @@ class FeatureExecutor {
475
489
  ? output !== undefined && output !== null
476
490
  ? output
477
491
  : {}
478
- : { error: error !== null && error !== void 0 ? error : 'Step failed' };
492
+ : Object.assign({ error: error !== null && error !== void 0 ? error : 'Step failed' }, (errorDetails != null ? { details: errorDetails } : {}));
479
493
  const resultStr = stringifyProcessorValue(value);
480
494
  const inputStr = stringifyProcessorValue(resolvedInput);
481
495
  const encKey = this.getProcessorResultEncryptionKey();
482
- const stepResult = Object.assign(Object.assign(Object.assign({}, (0, context_1.executionContextFields)()), { process_id: stepProcessId, product_id: this.productId || null, env: this.state.env, component: types_1.LogEventTypes.FEATURE_STEP, // step results always feature_step
483
- status, start: Date.now() - (duration || 0), end: Date.now(), retryable: true, result: encKey ? (0, processor_utils_1.encrypt)(resultStr, encKey) : resultStr, input: encKey ? (0, processor_utils_1.encrypt)(inputStr, encKey) : inputStr, feature_id: this.state.feature_id, feature_tag: this.state.feature_tag, product_tag: this.state.product, workspace_id: this.config.workspace_id, step_tag: step.tag, step_type: stepType, step_error: error, step_duration_ms: duration }), ((_a = this.functionInvocations.get(step.tag)) !== null && _a !== void 0 ? _a : {}));
496
+ const stepResult = Object.assign(Object.assign(Object.assign(Object.assign({}, (0, context_1.executionContextFields)()), ((_a = this.stepContexts.get(step.tag)) !== null && _a !== void 0 ? _a : {})), { process_id: stepProcessId, product_id: this.productId || null, env: this.state.env, component: types_1.LogEventTypes.FEATURE_STEP, // step results always feature_step
497
+ status, start: Date.now() - (duration || 0), end: Date.now(), retryable: true, result: encKey ? (0, processor_utils_1.encrypt)(resultStr, encKey) : resultStr, input: encKey ? (0, processor_utils_1.encrypt)(inputStr, encKey) : inputStr, feature_id: this.state.feature_id, feature_tag: this.state.feature_tag, product_tag: this.state.product, workspace_id: this.config.workspace_id, step_tag: step.tag, step_type: stepType, step_error: error, step_duration_ms: duration }), ((_b = this.functionInvocations.get(step.tag)) !== null && _b !== void 0 ? _b : {}));
484
498
  this.trace('step.persistence.sent', {
485
499
  step_tag: step.tag,
486
500
  step_type: stepType,
@@ -557,6 +571,7 @@ class FeatureExecutor {
557
571
  session_id: this.sessionLogFields.session_id,
558
572
  session_tag: this.sessionLogFields.session_tag,
559
573
  session_user_id: this.sessionLogFields.session_user_id,
574
+ asset_span_sink: this.assetSpans,
560
575
  });
561
576
  return (0, context_1.runWithExecutionContext)(context, () => this.executeInContext());
562
577
  }
@@ -659,7 +674,7 @@ class FeatureExecutor {
659
674
  }
660
675
  debugLog(`[FeatureExecutor] Step "${step.tag}" output:`, stepReturnValue);
661
676
  // Persist step result to backend (use step return shape, not raw primitive)
662
- await this.persistStepResult(step, result.success ? types_1.LogEventStatus.SUCCESS : types_1.LogEventStatus.FAIL, stepReturnValue, result.error, result.duration, result.input);
677
+ await this.persistStepResult(step, result.success ? types_1.LogEventStatus.SUCCESS : types_1.LogEventStatus.FAIL, stepReturnValue, result.error, result.duration, result.input, result.errorDetails);
663
678
  this.state.step_timings.push({
664
679
  tag: step.tag,
665
680
  duration_ms: result.duration,
@@ -825,6 +840,12 @@ class FeatureExecutor {
825
840
  process_id: `${this.state.feature_id}:${step.tag}`,
826
841
  parent_process_id: this.state.feature_id,
827
842
  }, parent);
843
+ this.stepContexts.set(step.tag, {
844
+ trace_id: context.trace_id,
845
+ span_id: context.span_id,
846
+ parent_span_id: context.parent_span_id,
847
+ step_run_id: context.step_run_id,
848
+ });
828
849
  return (0, context_1.runWithExecutionContext)(context, () => this.executeStepInContext(step));
829
850
  }
830
851
  async executeStepInContext(step) {
@@ -845,62 +866,67 @@ class FeatureExecutor {
845
866
  step_tag: step.tag,
846
867
  input: sanitizeForLog(resolvedInput),
847
868
  });
848
- let output;
849
- // Route steps to dedicated services; only action and notification use ProcessorService.
850
- switch (step.type) {
851
- case types_1.FeatureStepType.ACTION:
852
- output = await this.executeActionStep(step, resolvedInput);
853
- break;
854
- case types_1.FeatureStepType.DATABASE_ACTION:
855
- output = await this.executeDatabaseStep(step, resolvedInput);
856
- break;
857
- case types_1.FeatureStepType.NOTIFICATION:
858
- output = await this.executeNotificationStep(step, resolvedInput);
859
- break;
860
- case types_1.FeatureStepType.STORAGE:
861
- output = await this.executeStorageStep(step, resolvedInput);
862
- break;
863
- case types_1.FeatureStepType.PUBLISH:
864
- case types_1.FeatureStepType.PRODUCE:
865
- output = await this.executeProduceStep(step, resolvedInput);
866
- break;
867
- case types_1.FeatureStepType.GRAPH:
868
- output = await this.executeGraphStep(step, resolvedInput);
869
- break;
870
- case types_1.FeatureStepType.VECTOR:
871
- output = await this.executeVectorStep(step, resolvedInput);
872
- break;
873
- case types_1.FeatureStepType.SESSION:
874
- output = await this.executeSessionStep(step, resolvedInput);
875
- break;
876
- case types_1.FeatureStepType.FUNCTION:
877
- output = await this.executeFunctionStep(step, resolvedInput);
878
- break;
879
- case types_1.FeatureStepType.QUOTA:
880
- output = await this.executeQuotaStep(step, resolvedInput);
881
- break;
882
- case types_1.FeatureStepType.FALLBACK:
883
- output = await this.executeFallbackStep(step, resolvedInput);
884
- break;
885
- case types_1.FeatureStepType.CHILD_FEATURE:
886
- output = await this.executeChildWorkflowStep(step, resolvedInput);
887
- break;
888
- case types_1.FeatureStepType.SLEEP:
889
- await this.executeSleepStep(step, resolvedInput);
890
- output = { slept: true };
891
- break;
892
- case types_1.FeatureStepType.WAIT_FOR_SIGNAL:
893
- output = await this.executeWaitForSignalStep(step, resolvedInput);
894
- break;
895
- case types_1.FeatureStepType.CHECKPOINT:
896
- await this.executeCheckpointStep(step, resolvedInput);
897
- output = { checkpoint: step.tag };
898
- break;
899
- default:
900
- stepLog('Step type not implemented (passthrough)', { tag: step.tag, type: step.type });
901
- debugLog('[FeatureExecutor] executeStep unknown step type (passthrough)', { step_tag: step.tag, step_type: step.type });
902
- output = resolvedInput;
903
- }
869
+ const asset = this.describeStepAsset(step);
870
+ const runOperation = async () => {
871
+ let value;
872
+ // Route steps to dedicated services; only action and notification use ProcessorService.
873
+ switch (step.type) {
874
+ case types_1.FeatureStepType.ACTION:
875
+ value = await this.executeActionStep(step, resolvedInput);
876
+ break;
877
+ case types_1.FeatureStepType.DATABASE_ACTION:
878
+ value = await this.executeDatabaseStep(step, resolvedInput);
879
+ break;
880
+ case types_1.FeatureStepType.NOTIFICATION:
881
+ value = await this.executeNotificationStep(step, resolvedInput);
882
+ break;
883
+ case types_1.FeatureStepType.STORAGE:
884
+ value = await this.executeStorageStep(step, resolvedInput);
885
+ break;
886
+ case types_1.FeatureStepType.PUBLISH:
887
+ case types_1.FeatureStepType.PRODUCE:
888
+ value = await this.executeProduceStep(step, resolvedInput);
889
+ break;
890
+ case types_1.FeatureStepType.GRAPH:
891
+ value = await this.executeGraphStep(step, resolvedInput);
892
+ break;
893
+ case types_1.FeatureStepType.VECTOR:
894
+ value = await this.executeVectorStep(step, resolvedInput);
895
+ break;
896
+ case types_1.FeatureStepType.SESSION:
897
+ value = await this.executeSessionStep(step, resolvedInput);
898
+ break;
899
+ case types_1.FeatureStepType.FUNCTION:
900
+ value = await this.executeFunctionStep(step, resolvedInput);
901
+ break;
902
+ case types_1.FeatureStepType.QUOTA:
903
+ value = await this.executeQuotaStep(step, resolvedInput);
904
+ break;
905
+ case types_1.FeatureStepType.FALLBACK:
906
+ value = await this.executeFallbackStep(step, resolvedInput);
907
+ break;
908
+ case types_1.FeatureStepType.CHILD_FEATURE:
909
+ value = await this.executeChildWorkflowStep(step, resolvedInput);
910
+ break;
911
+ case types_1.FeatureStepType.SLEEP:
912
+ await this.executeSleepStep(step, resolvedInput);
913
+ value = { slept: true };
914
+ break;
915
+ case types_1.FeatureStepType.WAIT_FOR_SIGNAL:
916
+ value = await this.executeWaitForSignalStep(step, resolvedInput);
917
+ break;
918
+ case types_1.FeatureStepType.CHECKPOINT:
919
+ await this.executeCheckpointStep(step, resolvedInput);
920
+ value = { checkpoint: step.tag };
921
+ break;
922
+ default:
923
+ stepLog('Step type not implemented (passthrough)', { tag: step.tag, type: step.type });
924
+ debugLog('[FeatureExecutor] executeStep unknown step type (passthrough)', { step_tag: step.tag, step_type: step.type });
925
+ value = resolvedInput;
926
+ }
927
+ return value;
928
+ };
929
+ let output = asset ? await (0, context_1.withAssetSpan)(asset, runOperation) : await runOperation();
904
930
  // For action steps with no app: if step.output is a template with $ refs (e.g. $Sequence{main}{step-a}{value}-b),
905
931
  // resolve it so downstream steps get the correct value (checkpoint / closure-style steps).
906
932
  if (step.type === types_1.FeatureStepType.ACTION &&
@@ -950,13 +976,45 @@ class FeatureExecutor {
950
976
  success: false,
951
977
  input: resolvedInput,
952
978
  error: stepErrorMsg,
979
+ errorDetails: details.details,
953
980
  duration,
954
981
  };
955
982
  }
956
983
  }
957
- /**
958
- * Execute an action step
959
- */
984
+ describeStepAsset(step) {
985
+ var _a, _b;
986
+ const operation = step.event || 'execute';
987
+ switch (step.type) {
988
+ case types_1.FeatureStepType.ACTION:
989
+ return step.app ? { type: 'app', tag: step.app, operation, action: step.event } : null;
990
+ case types_1.FeatureStepType.DATABASE_ACTION:
991
+ return { type: 'database', tag: step.database || 'database', operation, action: step.event };
992
+ case types_1.FeatureStepType.GRAPH:
993
+ return { type: 'graph', tag: step.graph || 'graph', operation, action: step.event };
994
+ case types_1.FeatureStepType.VECTOR:
995
+ return { type: 'vector', tag: step.vector || 'vector', operation, action: step.event };
996
+ case types_1.FeatureStepType.STORAGE:
997
+ return { type: 'storage', tag: step.storage || 'storage', operation, action: step.event };
998
+ case types_1.FeatureStepType.NOTIFICATION:
999
+ return { type: 'notification', tag: step.notification || 'notification', operation, action: step.event };
1000
+ case types_1.FeatureStepType.PUBLISH:
1001
+ case types_1.FeatureStepType.PRODUCE:
1002
+ return { type: 'message_broker', tag: step.broker || 'message-broker', operation: 'produce', action: step.event };
1003
+ case types_1.FeatureStepType.SESSION:
1004
+ return { type: 'session', tag: step.session || 'session', operation, action: step.event };
1005
+ case types_1.FeatureStepType.QUOTA:
1006
+ return { type: 'quota', tag: step.quota || 'quota', operation: 'execute' };
1007
+ case types_1.FeatureStepType.FALLBACK:
1008
+ return { type: 'fallback', tag: step.fallback || 'fallback', operation: 'execute' };
1009
+ case types_1.FeatureStepType.CHILD_FEATURE:
1010
+ return { type: 'feature', tag: step.feature || 'feature', operation: 'execute' };
1011
+ case types_1.FeatureStepType.FUNCTION:
1012
+ return { type: 'function', tag: ((_a = step.function_ref) === null || _a === void 0 ? void 0 : _a.namespace) || 'function', operation: ((_b = step.function_ref) === null || _b === void 0 ? void 0 : _b.operation) || operation };
1013
+ default:
1014
+ return null;
1015
+ }
1016
+ }
1017
+ /** Execute an action step. */
960
1018
  async executeActionStep(step, input) {
961
1019
  var _a, _b;
962
1020
  debugLog('[FeatureExecutor] executeActionStep', { feature_id: this.state.feature_id, step_tag: step.tag, app: step.app });
@@ -2658,7 +2716,7 @@ class FeatureExecutor {
2658
2716
  stepReturnValueResume = undefined;
2659
2717
  }
2660
2718
  // Persist step result to backend (use step return shape, not raw primitive)
2661
- await this.persistStepResult(step, result.success ? types_1.LogEventStatus.SUCCESS : types_1.LogEventStatus.FAIL, stepReturnValueResume, result.error, result.duration, result.input);
2719
+ await this.persistStepResult(step, result.success ? types_1.LogEventStatus.SUCCESS : types_1.LogEventStatus.FAIL, stepReturnValueResume, result.error, result.duration, result.input, result.errorDetails);
2662
2720
  this.state.step_timings.push({
2663
2721
  tag: step.tag,
2664
2722
  duration_ms: result.duration,