@solidxai/core 0.1.13-beta.3 → 0.1.13-beta.4
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/commands/seed.command.d.ts +2 -0
- package/dist/commands/seed.command.d.ts.map +1 -1
- package/dist/commands/seed.command.js +21 -0
- package/dist/commands/seed.command.js.map +1 -1
- package/dist/entities/workflow-trigger-execution.entity.js +1 -1
- package/dist/entities/workflow-trigger-execution.entity.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts +1 -0
- package/dist/interfaces.d.ts.map +1 -1
- package/dist/interfaces.js.map +1 -1
- package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
- package/dist/seeders/module-metadata-seeder.service.js +44 -27
- package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
- package/dist/seeders/seed-data/solid-core-metadata.json +80 -67
- package/dist/services/workflow/nodes/execution-fail.node.d.ts +6 -0
- package/dist/services/workflow/nodes/execution-fail.node.d.ts.map +1 -0
- package/dist/services/workflow/nodes/execution-fail.node.js +81 -0
- package/dist/services/workflow/nodes/execution-fail.node.js.map +1 -0
- package/dist/services/workflow/nodes/for-each.node.d.ts +2 -0
- package/dist/services/workflow/nodes/for-each.node.d.ts.map +1 -1
- package/dist/services/workflow/nodes/for-each.node.js +114 -5
- package/dist/services/workflow/nodes/for-each.node.js.map +1 -1
- package/dist/services/workflow/nodes/if.node.d.ts.map +1 -1
- package/dist/services/workflow/nodes/if.node.js +7 -0
- package/dist/services/workflow/nodes/if.node.js.map +1 -1
- package/dist/services/workflow/nodes/log-write.node.d.ts.map +1 -1
- package/dist/services/workflow/nodes/log-write.node.js +2 -0
- package/dist/services/workflow/nodes/log-write.node.js.map +1 -1
- package/dist/services/workflow/nodes/loop-until.node.d.ts +12 -0
- package/dist/services/workflow/nodes/loop-until.node.d.ts.map +1 -0
- package/dist/services/workflow/nodes/loop-until.node.js +281 -0
- package/dist/services/workflow/nodes/loop-until.node.js.map +1 -0
- package/dist/services/workflow/nodes/parallel.node.d.ts.map +1 -1
- package/dist/services/workflow/nodes/parallel.node.js +7 -0
- package/dist/services/workflow/nodes/parallel.node.js.map +1 -1
- package/dist/services/workflow/nodes/sequential.node.d.ts.map +1 -1
- package/dist/services/workflow/nodes/sequential.node.js +7 -0
- package/dist/services/workflow/nodes/sequential.node.js.map +1 -1
- package/dist/services/workflow/nodes/switch.node.d.ts.map +1 -1
- package/dist/services/workflow/nodes/switch.node.js +7 -0
- package/dist/services/workflow/nodes/switch.node.js.map +1 -1
- package/dist/services/workflow/workflow-definition-validator.service.d.ts.map +1 -1
- package/dist/services/workflow/workflow-definition-validator.service.js +5 -2
- package/dist/services/workflow/workflow-definition-validator.service.js.map +1 -1
- package/dist/services/workflow/workflow-expression.service.d.ts.map +1 -1
- package/dist/services/workflow/workflow-expression.service.js +5 -0
- package/dist/services/workflow/workflow-expression.service.js.map +1 -1
- package/dist/services/workflow/workflow-node-registry.service.d.ts +2 -1
- package/dist/services/workflow/workflow-node-registry.service.d.ts.map +1 -1
- package/dist/services/workflow/workflow-node-registry.service.js +7 -0
- package/dist/services/workflow/workflow-node-registry.service.js.map +1 -1
- package/dist/services/workflow/workflow-runtime.service.d.ts +8 -0
- package/dist/services/workflow/workflow-runtime.service.d.ts.map +1 -1
- package/dist/services/workflow/workflow-runtime.service.js +197 -32
- package/dist/services/workflow/workflow-runtime.service.js.map +1 -1
- package/dist/solid-core.module.d.ts.map +1 -1
- package/dist/solid-core.module.js +4 -0
- package/dist/solid-core.module.js.map +1 -1
- package/dist/types/workflow-dsl.types.d.ts +14 -0
- package/dist/types/workflow-dsl.types.d.ts.map +1 -1
- package/dist/types/workflow-dsl.types.js.map +1 -1
- package/dist-tests/api/authenticate.spec.js +119 -0
- package/dist-tests/api/authenticate.spec.js.map +1 -0
- package/dist-tests/api/crud-service.findOne.cityMaster.spec.js +97 -0
- package/dist-tests/api/crud-service.findOne.cityMaster.spec.js.map +1 -0
- package/dist-tests/api/ping.spec.js +21 -0
- package/dist-tests/api/ping.spec.js.map +1 -0
- package/dist-tests/helpers/auth.js +41 -0
- package/dist-tests/helpers/auth.js.map +1 -0
- package/dist-tests/helpers/env.js +11 -0
- package/dist-tests/helpers/env.js.map +1 -0
- package/docs/agent-builder/notebook-lm-prompt-for-agent-builder.md +136 -0
- package/docs/agent-builder/team-ready-note-agent-builder.md +305 -0
- package/docs/agent-hub-grooming.md +301 -0
- package/docs/dashboards/AGENTIC_DASHBOARD_IMPLEMENTATION_PLAN.md +438 -0
- package/docs/dashboards/dashboard-curl-smoke-tests.txt +146 -0
- package/docs/dashboards/delete-legacy-dashboard-metadata.sql +172 -0
- package/docs/datasource-introspection-ddl-analysis.md +326 -0
- package/docs/datasource-introspection-implementation-plan.md +306 -0
- package/docs/grouping-enhancements.md +89 -0
- package/docs/java-spring/README.md +3 -0
- package/docs/java-spring/solid-core-module-deep-dive-report.md +1317 -0
- package/docs/module-package-import-handoff.md +691 -0
- package/docs/seed-changes.md +65 -0
- package/docs/test-data-workflow.md +200 -0
- package/docs/type-declaration-import-issue.md +24 -0
- package/docs/workflow/business-automation-example-notes.md +309 -0
- package/docs/workflow/control-flow-node-addition-sop.md +324 -0
- package/docs/workflow/data-engineering-pipeline-example-notes.md +330 -0
- package/docs/workflow/foreach-example-notes.md +187 -0
- package/docs/workflow/hello-world-example-notes.md +271 -0
- package/docs/workflow/kestra-concepts-plugins-blueprints.md +315 -0
- package/docs/workflow/loop-until-example-notes.md +198 -0
- package/docs/workflow/microservices-and-apis-example-notes.md +264 -0
- package/docs/workflow/samples.md +25 -0
- package/docs/workflow/what-is-kestra.md +79 -0
- package/docs/workflow/workflow-core-module-handoff-summary.md +191 -0
- package/docs/workflow/workflow-module-brd.md +185 -0
- package/docs/workflow/workflow-module-domain-model.md +252 -0
- package/docs/workflow/workflow-module-metadata-dsl.md +302 -0
- package/docs/workflow/workflow-module-technical-spec.md +293 -0
- package/docs/workflow/workflow-node-type-contracts.md +635 -0
- package/docs/workflow/workflow-node-ui-metadata-contract.md +1262 -0
- package/docs/workflow/workflow-solidx-model-field-spec.md +284 -0
- package/package.json +1 -1
- package/src/commands/seed.command.ts +19 -0
- package/src/entities/workflow-trigger-execution.entity.ts +1 -1
- package/src/index.ts +2 -0
- package/src/interfaces.ts +1 -0
- package/src/seeders/module-metadata-seeder.service.ts +50 -36
- package/src/seeders/seed-data/solid-core-metadata.json +80 -67
- package/src/services/workflow/nodes/execution-fail.node.ts +82 -0
- package/src/services/workflow/nodes/for-each.node.ts +140 -6
- package/src/services/workflow/nodes/if.node.ts +7 -0
- package/src/services/workflow/nodes/log-write.node.ts +2 -0
- package/src/services/workflow/nodes/loop-until.node.ts +343 -0
- package/src/services/workflow/nodes/parallel.node.ts +7 -0
- package/src/services/workflow/nodes/sequential.node.ts +7 -0
- package/src/services/workflow/nodes/switch.node.ts +7 -0
- package/src/services/workflow/workflow-definition-validator.service.ts +5 -2
- package/src/services/workflow/workflow-expression.service.ts +5 -0
- package/src/services/workflow/workflow-node-registry.service.ts +11 -0
- package/src/services/workflow/workflow-runtime.service.ts +274 -39
- package/src/solid-core.module.ts +4 -0
- package/src/types/workflow-dsl.types.ts +43 -0
- package/.claude/settings.local.json +0 -16
- package/CLAUDE.md +0 -26
- package/src/services/1.js +0 -6
|
@@ -161,7 +161,11 @@ export class WorkflowRuntimeService {
|
|
|
161
161
|
const execution = existingExecution
|
|
162
162
|
? await this.writer.startExecution(existingExecution, effectiveRequest)
|
|
163
163
|
: await this.writer.createExecution(definition, effectiveRequest);
|
|
164
|
-
const nodeCount = this.countNodes(
|
|
164
|
+
const nodeCount = this.countNodes([
|
|
165
|
+
...(definitionDsl.nodes ?? []),
|
|
166
|
+
...(definitionDsl.errors ?? []),
|
|
167
|
+
...(definitionDsl.finally ?? []),
|
|
168
|
+
]);
|
|
165
169
|
const outputs: Record<string, any> = {};
|
|
166
170
|
const runtimeContext: WorkflowRuntimeContext = {
|
|
167
171
|
execution,
|
|
@@ -175,26 +179,52 @@ export class WorkflowRuntimeService {
|
|
|
175
179
|
},
|
|
176
180
|
};
|
|
177
181
|
|
|
182
|
+
this.logger.log(
|
|
183
|
+
`Starting workflow execution ${execution.executionIdentifier} for ${definition.key} with ${nodeCount} node(s).`,
|
|
184
|
+
);
|
|
185
|
+
await this.writer.writeLog(execution, undefined, {
|
|
186
|
+
level: 'info',
|
|
187
|
+
eventType: 'execution.started',
|
|
188
|
+
message: `Workflow execution started for ${definition.key}.`,
|
|
189
|
+
metadata: {
|
|
190
|
+
executionIdentifier: execution.executionIdentifier,
|
|
191
|
+
workflowKey: definition.key,
|
|
192
|
+
triggerType: execution.triggerType,
|
|
193
|
+
nodeCount,
|
|
194
|
+
inputKeys: Object.keys(runtimeContext.input ?? {}),
|
|
195
|
+
variableKeys: Object.keys(runtimeContext.variables ?? {}),
|
|
196
|
+
},
|
|
197
|
+
}, this.nextLogSequence(runtimeContext));
|
|
198
|
+
|
|
199
|
+
let executionError: unknown;
|
|
200
|
+
|
|
178
201
|
try {
|
|
179
|
-
this.
|
|
180
|
-
|
|
181
|
-
|
|
202
|
+
await this.runNodes(definitionDsl.nodes, runtimeContext);
|
|
203
|
+
} catch (error) {
|
|
204
|
+
executionError = error;
|
|
205
|
+
await this.runGlobalErrorHandlers(definitionDsl, runtimeContext, error);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
try {
|
|
209
|
+
await this.runFinallyHandlers(definitionDsl, runtimeContext);
|
|
210
|
+
} catch (finallyError) {
|
|
182
211
|
await this.writer.writeLog(execution, undefined, {
|
|
183
|
-
level: '
|
|
184
|
-
eventType: '
|
|
185
|
-
message: `
|
|
212
|
+
level: 'error',
|
|
213
|
+
eventType: 'finally.failed',
|
|
214
|
+
message: `Finally handler failed: ${this.errorMessage(finallyError)}.`,
|
|
215
|
+
context: this.summarizeError(finallyError),
|
|
186
216
|
metadata: {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
nodeCount,
|
|
191
|
-
inputKeys: Object.keys(runtimeContext.input ?? {}),
|
|
192
|
-
variableKeys: Object.keys(runtimeContext.variables ?? {}),
|
|
217
|
+
originalError: executionError
|
|
218
|
+
? this.summarizeError(executionError)
|
|
219
|
+
: undefined,
|
|
193
220
|
},
|
|
194
221
|
}, this.nextLogSequence(runtimeContext));
|
|
222
|
+
if (!executionError) {
|
|
223
|
+
executionError = finallyError;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
195
226
|
|
|
196
|
-
|
|
197
|
-
|
|
227
|
+
if (!executionError) {
|
|
198
228
|
const completed = await this.writer.completeExecution(execution, outputs);
|
|
199
229
|
|
|
200
230
|
this.logger.log(
|
|
@@ -212,26 +242,26 @@ export class WorkflowRuntimeService {
|
|
|
212
242
|
}, this.nextLogSequence(runtimeContext));
|
|
213
243
|
|
|
214
244
|
return this.toResponse(completed);
|
|
215
|
-
}
|
|
216
|
-
const failed = await this.writer.failExecution(execution, error);
|
|
245
|
+
}
|
|
217
246
|
|
|
218
|
-
|
|
219
|
-
`Failed workflow execution ${failed.executionIdentifier} for ${definition.key}: ${failed.errorSummary}`,
|
|
220
|
-
error instanceof Error ? error.stack : undefined,
|
|
221
|
-
);
|
|
222
|
-
await this.writer.writeLog(failed, undefined, {
|
|
223
|
-
level: 'error',
|
|
224
|
-
eventType: 'execution.failed',
|
|
225
|
-
message: failed.errorSummary,
|
|
226
|
-
context: this.summarizeError(error),
|
|
227
|
-
metadata: {
|
|
228
|
-
executionIdentifier: failed.executionIdentifier,
|
|
229
|
-
durationMs: failed.durationMs,
|
|
230
|
-
},
|
|
231
|
-
}, this.nextLogSequence(runtimeContext));
|
|
247
|
+
const failed = await this.writer.failExecution(execution, executionError);
|
|
232
248
|
|
|
233
|
-
|
|
234
|
-
|
|
249
|
+
this.logger.error(
|
|
250
|
+
`Failed workflow execution ${failed.executionIdentifier} for ${definition.key}: ${failed.errorSummary}`,
|
|
251
|
+
executionError instanceof Error ? executionError.stack : undefined,
|
|
252
|
+
);
|
|
253
|
+
await this.writer.writeLog(failed, undefined, {
|
|
254
|
+
level: 'error',
|
|
255
|
+
eventType: 'execution.failed',
|
|
256
|
+
message: failed.errorSummary,
|
|
257
|
+
context: this.summarizeError(executionError),
|
|
258
|
+
metadata: {
|
|
259
|
+
executionIdentifier: failed.executionIdentifier,
|
|
260
|
+
durationMs: failed.durationMs,
|
|
261
|
+
},
|
|
262
|
+
}, this.nextLogSequence(runtimeContext));
|
|
263
|
+
|
|
264
|
+
return this.toResponse(failed);
|
|
235
265
|
}
|
|
236
266
|
|
|
237
267
|
async getExecutionStatus(executionId: number): Promise<WorkflowExecutionResponse> {
|
|
@@ -363,17 +393,19 @@ export class WorkflowRuntimeService {
|
|
|
363
393
|
nodes: WorkflowNodeDefinition[],
|
|
364
394
|
context: WorkflowRuntimeContext,
|
|
365
395
|
): Promise<Record<string, any>> {
|
|
396
|
+
const nodeOutputs: Record<string, any> = {};
|
|
397
|
+
|
|
366
398
|
for (const node of nodes ?? []) {
|
|
367
|
-
await this.runNode(node, context);
|
|
399
|
+
nodeOutputs[node.id] = await this.runNode(node, context);
|
|
368
400
|
}
|
|
369
401
|
|
|
370
|
-
return
|
|
402
|
+
return nodeOutputs;
|
|
371
403
|
}
|
|
372
404
|
|
|
373
405
|
private async runNode(
|
|
374
406
|
node: WorkflowNodeDefinition,
|
|
375
407
|
context: WorkflowRuntimeContext,
|
|
376
|
-
): Promise<
|
|
408
|
+
): Promise<Record<string, any>> {
|
|
377
409
|
const inputPayload = {
|
|
378
410
|
configuration: node.configuration,
|
|
379
411
|
input: context.input,
|
|
@@ -400,7 +432,7 @@ export class WorkflowRuntimeService {
|
|
|
400
432
|
message: `Skipped disabled node ${node.id}.`,
|
|
401
433
|
metadata: this.nodeLogMetadata(node, context, step),
|
|
402
434
|
}, this.nextLogSequence(context));
|
|
403
|
-
return;
|
|
435
|
+
return context.outputs[node.id];
|
|
404
436
|
}
|
|
405
437
|
|
|
406
438
|
try {
|
|
@@ -444,7 +476,7 @@ export class WorkflowRuntimeService {
|
|
|
444
476
|
});
|
|
445
477
|
|
|
446
478
|
const output = result.output ?? {};
|
|
447
|
-
context.outputs[node.id] = output;
|
|
479
|
+
context.outputs[node.id] = this.getRuntimeContextOutput(node, output);
|
|
448
480
|
|
|
449
481
|
for (const artifact of result.artifacts ?? []) {
|
|
450
482
|
await this.writer.writeArtifact(context.execution, step, artifact);
|
|
@@ -472,6 +504,8 @@ export class WorkflowRuntimeService {
|
|
|
472
504
|
artifactCount: result.artifacts?.length ?? 0,
|
|
473
505
|
},
|
|
474
506
|
}, this.nextLogSequence(context));
|
|
507
|
+
|
|
508
|
+
return output;
|
|
475
509
|
} catch (error) {
|
|
476
510
|
await this.writer.failStep(step, error);
|
|
477
511
|
|
|
@@ -486,7 +520,7 @@ export class WorkflowRuntimeService {
|
|
|
486
520
|
context: this.summarizeError(error),
|
|
487
521
|
metadata: this.nodeLogMetadata(node, context, step),
|
|
488
522
|
}, this.nextLogSequence(context));
|
|
489
|
-
return;
|
|
523
|
+
return context.outputs[node.id];
|
|
490
524
|
}
|
|
491
525
|
|
|
492
526
|
await this.writer.writeLog(context.execution, step, {
|
|
@@ -496,10 +530,158 @@ export class WorkflowRuntimeService {
|
|
|
496
530
|
context: this.summarizeError(error),
|
|
497
531
|
metadata: this.nodeLogMetadata(node, context, step),
|
|
498
532
|
}, this.nextLogSequence(context));
|
|
533
|
+
await this.runLocalErrorHandlers(node, context, error);
|
|
499
534
|
throw error;
|
|
500
535
|
}
|
|
501
536
|
}
|
|
502
537
|
|
|
538
|
+
private async runGlobalErrorHandlers(
|
|
539
|
+
definitionDsl: WorkflowDefinitionDsl,
|
|
540
|
+
context: WorkflowRuntimeContext,
|
|
541
|
+
error: unknown,
|
|
542
|
+
): Promise<void> {
|
|
543
|
+
const errorNodes = definitionDsl.errors ?? [];
|
|
544
|
+
if (!errorNodes.length) {
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
await this.runErrorHandlers(
|
|
549
|
+
errorNodes,
|
|
550
|
+
context,
|
|
551
|
+
error,
|
|
552
|
+
'global',
|
|
553
|
+
undefined,
|
|
554
|
+
undefined,
|
|
555
|
+
);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
private async runFinallyHandlers(
|
|
559
|
+
definitionDsl: WorkflowDefinitionDsl,
|
|
560
|
+
context: WorkflowRuntimeContext,
|
|
561
|
+
): Promise<void> {
|
|
562
|
+
const finallyNodes = definitionDsl.finally ?? [];
|
|
563
|
+
if (!finallyNodes.length) {
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
await this.writer.writeLog(context.execution, undefined, {
|
|
568
|
+
level: 'info',
|
|
569
|
+
eventType: 'finally.started',
|
|
570
|
+
message: 'Running workflow finally handlers.',
|
|
571
|
+
metadata: {
|
|
572
|
+
handlerNodeCount: finallyNodes.length,
|
|
573
|
+
},
|
|
574
|
+
}, this.nextLogSequence(context));
|
|
575
|
+
|
|
576
|
+
await this.runNodes(finallyNodes, context);
|
|
577
|
+
|
|
578
|
+
await this.writer.writeLog(context.execution, undefined, {
|
|
579
|
+
level: 'info',
|
|
580
|
+
eventType: 'finally.completed',
|
|
581
|
+
message: 'Workflow finally handlers completed.',
|
|
582
|
+
metadata: {
|
|
583
|
+
handlerNodeCount: finallyNodes.length,
|
|
584
|
+
},
|
|
585
|
+
}, this.nextLogSequence(context));
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
private async runLocalErrorHandlers(
|
|
589
|
+
node: WorkflowNodeDefinition,
|
|
590
|
+
context: WorkflowRuntimeContext,
|
|
591
|
+
error: unknown,
|
|
592
|
+
): Promise<void> {
|
|
593
|
+
const errorNodes = node.errors ?? [];
|
|
594
|
+
if (!errorNodes.length) {
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
await this.runErrorHandlers(
|
|
599
|
+
errorNodes,
|
|
600
|
+
context,
|
|
601
|
+
error,
|
|
602
|
+
'local',
|
|
603
|
+
node.id,
|
|
604
|
+
context.stepExecution?.stepExecutionKey,
|
|
605
|
+
);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
private async runErrorHandlers(
|
|
609
|
+
errorNodes: WorkflowNodeDefinition[],
|
|
610
|
+
context: WorkflowRuntimeContext,
|
|
611
|
+
error: unknown,
|
|
612
|
+
scope: 'global' | 'local',
|
|
613
|
+
sourceNodeId?: string,
|
|
614
|
+
sourceStepExecutionKey?: string,
|
|
615
|
+
): Promise<void> {
|
|
616
|
+
const errorContext = this.buildErrorContext(error, sourceNodeId, sourceStepExecutionKey);
|
|
617
|
+
|
|
618
|
+
await this.writer.writeLog(context.execution, undefined, {
|
|
619
|
+
level: 'warn',
|
|
620
|
+
eventType: `error-handler.${scope}.started`,
|
|
621
|
+
message:
|
|
622
|
+
scope === 'global'
|
|
623
|
+
? 'Running workflow-level error handlers.'
|
|
624
|
+
: `Running local error handlers for node ${sourceNodeId}.`,
|
|
625
|
+
context: errorContext,
|
|
626
|
+
metadata: {
|
|
627
|
+
sourceNodeId,
|
|
628
|
+
sourceStepExecutionKey,
|
|
629
|
+
handlerNodeCount: errorNodes.length,
|
|
630
|
+
},
|
|
631
|
+
}, this.nextLogSequence(context));
|
|
632
|
+
|
|
633
|
+
try {
|
|
634
|
+
await this.runNodes(errorNodes, {
|
|
635
|
+
...context,
|
|
636
|
+
error: errorContext,
|
|
637
|
+
parentNodeId: sourceNodeId ?? context.parentNodeId,
|
|
638
|
+
parentStepExecutionKey:
|
|
639
|
+
sourceStepExecutionKey ?? context.parentStepExecutionKey,
|
|
640
|
+
});
|
|
641
|
+
} catch (handlerError) {
|
|
642
|
+
await this.writer.writeLog(context.execution, undefined, {
|
|
643
|
+
level: 'error',
|
|
644
|
+
eventType: `error-handler.${scope}.failed`,
|
|
645
|
+
message: `Error handler failed: ${this.errorMessage(handlerError)}.`,
|
|
646
|
+
context: this.summarizeError(handlerError),
|
|
647
|
+
metadata: {
|
|
648
|
+
originalError: errorContext,
|
|
649
|
+
sourceNodeId,
|
|
650
|
+
sourceStepExecutionKey,
|
|
651
|
+
},
|
|
652
|
+
}, this.nextLogSequence(context));
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
await this.writer.writeLog(context.execution, undefined, {
|
|
657
|
+
level: 'info',
|
|
658
|
+
eventType: `error-handler.${scope}.completed`,
|
|
659
|
+
message:
|
|
660
|
+
scope === 'global'
|
|
661
|
+
? 'Workflow-level error handlers completed.'
|
|
662
|
+
: `Local error handlers completed for node ${sourceNodeId}.`,
|
|
663
|
+
context: errorContext,
|
|
664
|
+
metadata: {
|
|
665
|
+
sourceNodeId,
|
|
666
|
+
sourceStepExecutionKey,
|
|
667
|
+
},
|
|
668
|
+
}, this.nextLogSequence(context));
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
private buildErrorContext(
|
|
672
|
+
error: unknown,
|
|
673
|
+
nodeId?: string,
|
|
674
|
+
stepExecutionKey?: string,
|
|
675
|
+
): Record<string, any> {
|
|
676
|
+
const summary = this.summarizeError(error);
|
|
677
|
+
return {
|
|
678
|
+
...summary,
|
|
679
|
+
message: this.errorMessage(error),
|
|
680
|
+
nodeId,
|
|
681
|
+
stepExecutionKey,
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
|
|
503
685
|
private assertDefinitionYaml(value: any): WorkflowDefinitionDsl {
|
|
504
686
|
if (!value || typeof value !== 'string') {
|
|
505
687
|
throw new BadRequestException(
|
|
@@ -627,6 +809,7 @@ export class WorkflowRuntimeService {
|
|
|
627
809
|
...(node.then ?? []),
|
|
628
810
|
...(node.else ?? []),
|
|
629
811
|
...(node.defaults ?? []),
|
|
812
|
+
...(node.errors ?? []),
|
|
630
813
|
...Object.values(node.cases ?? {}).flat(),
|
|
631
814
|
];
|
|
632
815
|
|
|
@@ -660,6 +843,58 @@ export class WorkflowRuntimeService {
|
|
|
660
843
|
};
|
|
661
844
|
}
|
|
662
845
|
|
|
846
|
+
private getRuntimeContextOutput(
|
|
847
|
+
node: WorkflowNodeDefinition,
|
|
848
|
+
output: Record<string, any>,
|
|
849
|
+
): Record<string, any> {
|
|
850
|
+
const hiddenOutputPaths =
|
|
851
|
+
this.registry
|
|
852
|
+
.getMetadata(node.type)
|
|
853
|
+
.authoring?.outputs?.filter(
|
|
854
|
+
(definition) => definition.includeInRuntimeContext === false,
|
|
855
|
+
)
|
|
856
|
+
.map((definition) => definition.path ?? definition.key)
|
|
857
|
+
.filter(Boolean) ?? [];
|
|
858
|
+
|
|
859
|
+
if (!hiddenOutputPaths.length || !output || typeof output !== 'object') {
|
|
860
|
+
return output;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
const runtimeOutput = this.cloneOutput(output);
|
|
864
|
+
hiddenOutputPaths.forEach((path) => {
|
|
865
|
+
this.deletePath(runtimeOutput, path);
|
|
866
|
+
});
|
|
867
|
+
|
|
868
|
+
return runtimeOutput;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
private cloneOutput(output: Record<string, any>): Record<string, any> {
|
|
872
|
+
if (typeof structuredClone === 'function') {
|
|
873
|
+
return structuredClone(output);
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
return JSON.parse(JSON.stringify(output));
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
private deletePath(target: Record<string, any>, path: string) {
|
|
880
|
+
const parts = path.split('.').filter(Boolean);
|
|
881
|
+
if (!parts.length) {
|
|
882
|
+
return;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
let cursor: any = target;
|
|
886
|
+
for (let index = 0; index < parts.length - 1; index += 1) {
|
|
887
|
+
cursor = cursor?.[parts[index]];
|
|
888
|
+
if (!cursor || typeof cursor !== 'object') {
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
if (cursor && typeof cursor === 'object') {
|
|
894
|
+
delete cursor[parts[parts.length - 1]];
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
|
|
663
898
|
private summarizeValue(value: any): any {
|
|
664
899
|
if (Array.isArray(value)) {
|
|
665
900
|
return {
|
package/src/solid-core.module.ts
CHANGED
|
@@ -441,10 +441,12 @@ import { WorkflowInvocationService } from './services/workflow/workflow-invocati
|
|
|
441
441
|
import { WorkflowNodeRegistryService } from './services/workflow/workflow-node-registry.service';
|
|
442
442
|
import { WorkflowRuntimeService } from './services/workflow/workflow-runtime.service';
|
|
443
443
|
import { WorkflowScheduledTriggerJobService } from './services/workflow/workflow-scheduled-trigger.job';
|
|
444
|
+
import { ExecutionFailNode } from './services/workflow/nodes/execution-fail.node';
|
|
444
445
|
import { ForEachNode } from './services/workflow/nodes/for-each.node';
|
|
445
446
|
import { HttpRequestNode } from './services/workflow/nodes/http-request.node';
|
|
446
447
|
import { IfNode } from './services/workflow/nodes/if.node';
|
|
447
448
|
import { LogWriteNode } from './services/workflow/nodes/log-write.node';
|
|
449
|
+
import { LoopUntilNode } from './services/workflow/nodes/loop-until.node';
|
|
448
450
|
import { ParallelNode } from './services/workflow/nodes/parallel.node';
|
|
449
451
|
import { RuntimePythonNode } from './services/workflow/nodes/runtime-python.node';
|
|
450
452
|
import { SequentialNode } from './services/workflow/nodes/sequential.node';
|
|
@@ -947,10 +949,12 @@ import { SwitchNode } from './services/workflow/nodes/switch.node';
|
|
|
947
949
|
WorkflowDefinitionValidatorService,
|
|
948
950
|
WorkflowNodeRegistryService,
|
|
949
951
|
WorkflowScheduledTriggerJobService,
|
|
952
|
+
ExecutionFailNode,
|
|
950
953
|
LogWriteNode,
|
|
951
954
|
HttpRequestNode,
|
|
952
955
|
IfNode,
|
|
953
956
|
ForEachNode,
|
|
957
|
+
LoopUntilNode,
|
|
954
958
|
ParallelNode,
|
|
955
959
|
RuntimePythonNode,
|
|
956
960
|
SequentialNode,
|
|
@@ -200,6 +200,9 @@ export interface WorkflowNodeDefinition {
|
|
|
200
200
|
/** Child nodes executed when no `switch.cases` entry matches the switch value. */
|
|
201
201
|
defaults?: WorkflowNodeDefinition[];
|
|
202
202
|
|
|
203
|
+
/** Child nodes executed when this node or its child subtree fails. */
|
|
204
|
+
errors?: WorkflowNodeDefinition[];
|
|
205
|
+
|
|
203
206
|
/**
|
|
204
207
|
* Named child-node collections for `switch`.
|
|
205
208
|
*
|
|
@@ -287,6 +290,12 @@ export interface WorkflowDefinitionDsl {
|
|
|
287
290
|
/** Optional workflow triggers that can create executions. */
|
|
288
291
|
triggers?: WorkflowTriggerDefinition[];
|
|
289
292
|
|
|
293
|
+
/** Workflow-level error handler nodes executed sequentially when execution fails. */
|
|
294
|
+
errors?: WorkflowNodeDefinition[];
|
|
295
|
+
|
|
296
|
+
/** Workflow-level cleanup nodes executed sequentially after success or failure. */
|
|
297
|
+
finally?: WorkflowNodeDefinition[];
|
|
298
|
+
|
|
290
299
|
/** Workflow-level custom annotations for tooling. */
|
|
291
300
|
metadata?: Record<string, any>;
|
|
292
301
|
}
|
|
@@ -578,6 +587,13 @@ export interface WorkflowNodeOutputDefinition {
|
|
|
578
587
|
/** Whether the output is expected on successful execution. */
|
|
579
588
|
required?: boolean;
|
|
580
589
|
|
|
590
|
+
/**
|
|
591
|
+
* Whether this output is added to `outputs.<nodeId>` for downstream expressions.
|
|
592
|
+
* Defaults to true. Set false for observability-only outputs that should be
|
|
593
|
+
* stored on the step execution but not suggested or exposed to later nodes.
|
|
594
|
+
*/
|
|
595
|
+
includeInRuntimeContext?: boolean;
|
|
596
|
+
|
|
581
597
|
/** Optional machine schema for this output value. */
|
|
582
598
|
schema?: Record<string, any>;
|
|
583
599
|
}
|
|
@@ -867,6 +883,21 @@ export interface WorkflowExpressionResolver {
|
|
|
867
883
|
resolveExpression(expression: string, context: WorkflowRuntimeContext): any;
|
|
868
884
|
}
|
|
869
885
|
|
|
886
|
+
/** Loop context exposed to expressions for nested itemized controls. */
|
|
887
|
+
export interface WorkflowLoopContext {
|
|
888
|
+
/** Current item for this loop frame. */
|
|
889
|
+
item: any;
|
|
890
|
+
|
|
891
|
+
/** Zero-based iteration index for this loop frame. */
|
|
892
|
+
index: number;
|
|
893
|
+
|
|
894
|
+
/** Loop control node id. */
|
|
895
|
+
nodeId?: string;
|
|
896
|
+
|
|
897
|
+
/** Loop control step execution key. */
|
|
898
|
+
stepExecutionKey?: string;
|
|
899
|
+
}
|
|
900
|
+
|
|
870
901
|
/** Runtime context shared by workflow execution and node execution. */
|
|
871
902
|
export interface WorkflowRuntimeContext {
|
|
872
903
|
/** Parent workflow execution entity. */
|
|
@@ -905,6 +936,18 @@ export interface WorkflowRuntimeContext {
|
|
|
905
936
|
/** Current item index for itemized/iterative control nodes. */
|
|
906
937
|
index?: number;
|
|
907
938
|
|
|
939
|
+
/** Nearest parent loop frame, when inside nested loop children. */
|
|
940
|
+
parent?: WorkflowLoopContext;
|
|
941
|
+
|
|
942
|
+
/** Parent loop frames, nearest first. */
|
|
943
|
+
parents?: WorkflowLoopContext[];
|
|
944
|
+
|
|
945
|
+
/** Loop frames from outermost to innermost, including the current loop. */
|
|
946
|
+
loops?: WorkflowLoopContext[];
|
|
947
|
+
|
|
948
|
+
/** Current error context when executing an error handler. */
|
|
949
|
+
error?: any;
|
|
950
|
+
|
|
908
951
|
/** Parent control node id when executing nested child nodes. */
|
|
909
952
|
parentNodeId?: string;
|
|
910
953
|
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"permissions": {
|
|
3
|
-
"allow": [
|
|
4
|
-
"Bash(node -e:*)",
|
|
5
|
-
"WebFetch(domain:docs.solidxai.com)",
|
|
6
|
-
"WebFetch(domain:github.com)",
|
|
7
|
-
"Read(//Users/oswald/projects/Solid_Starters/solidctl/**)",
|
|
8
|
-
"Read(//Users/oswald/projects/Solid_Starters/**)",
|
|
9
|
-
"Bash(find /Users/oswald/projects/Solid_Starters/solid-core-module -type d -name migration* -o -name *database*)",
|
|
10
|
-
"Bash(node verify-imports.js)"
|
|
11
|
-
],
|
|
12
|
-
"additionalDirectories": [
|
|
13
|
-
"/Users/oswald/projects/Solid_Starters/solidctl"
|
|
14
|
-
]
|
|
15
|
-
}
|
|
16
|
-
}
|
package/CLAUDE.md
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# This is the SolidX API project.
|
|
2
|
-
This is included as a dependency in consuming projects.
|
|
3
|
-
|
|
4
|
-
# SolidX UI
|
|
5
|
-
# The corresponding UI project is at the below path:
|
|
6
|
-
/Users/oswald/projects/Solid_Starters/solid-core-ui
|
|
7
|
-
|
|
8
|
-
# SolidX Docs
|
|
9
|
-
# The documentation project is at the below path:
|
|
10
|
-
/Users/oswald/projects/solidxai-docs
|
|
11
|
-
|
|
12
|
-
# SolidX Agent
|
|
13
|
-
# The agent project which has the skills for helping users configure, build and use SolidX is at the below path:
|
|
14
|
-
/Users/oswald/projects/Solid_Starters/agent
|
|
15
|
-
|
|
16
|
-
# SolidX Control Plane Commands
|
|
17
|
-
# The control plane commands for managing SolidX instances are in the below path:
|
|
18
|
-
/Users/oswald/projects/Solid_Starters/solidctl
|
|
19
|
-
|
|
20
|
-
# Testing reference project
|
|
21
|
-
# This is the reference library management project that is used for testing and development of SolidX features. It is located at the below path:
|
|
22
|
-
/Users/oswald/projects/Solid_Starters/solid-library-management
|
|
23
|
-
|
|
24
|
-
# Code Builder project
|
|
25
|
-
# This is the project that contains the code builder which generates code based on user input and templates. It is located at the below path:
|
|
26
|
-
/Users/oswald/projects/Solid_Starters/solid-code-builder
|
package/src/services/1.js
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
1. Do i need to create a storeStreams method for aws service too?
|
|
2
|
-
- Handle later
|
|
3
|
-
2. queues handling -> if queues is enabled by default, i.e triggerExport(exportTransactionEntity.id).
|
|
4
|
-
- startExport should either return the data or return the transaction id
|
|
5
|
-
3. How to handle scenarios wherein, nested related exist.(do i need to only get the userkey)
|
|
6
|
-
- show the userKey
|