@girverket/xenocline 0.0.9
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/LICENSE.md +66 -0
- package/README.md +739 -0
- package/dist/aggregator.d.ts +53 -0
- package/dist/aggregator.js +31 -0
- package/dist/aggregator.js.map +1 -0
- package/dist/constants.d.ts +2 -0
- package/dist/context.d.ts +3 -0
- package/dist/event/aggregator.d.ts +16 -0
- package/dist/event/aggregator.js +29 -0
- package/dist/event/aggregator.js.map +1 -0
- package/dist/event/event.d.ts +14 -0
- package/dist/event/event.js +12 -0
- package/dist/event/event.js.map +1 -0
- package/dist/event/handler.d.ts +7 -0
- package/dist/event/handler.js +8 -0
- package/dist/event/handler.js.map +1 -0
- package/dist/event/node.d.ts +40 -0
- package/dist/event/node.js +24 -0
- package/dist/event/node.js.map +1 -0
- package/dist/event/phase.d.ts +15 -0
- package/dist/event/phase.js +12 -0
- package/dist/event/phase.js.map +1 -0
- package/dist/event/process.d.ts +14 -0
- package/dist/event/process.js +15 -0
- package/dist/event/process.js.map +1 -0
- package/dist/event/transition.d.ts +45 -0
- package/dist/event/transition.js +35 -0
- package/dist/event/transition.js.map +1 -0
- package/dist/event.d.ts +30 -0
- package/dist/execution/aggregator.d.ts +23 -0
- package/dist/execution/aggregator.js +81 -0
- package/dist/execution/aggregator.js.map +1 -0
- package/dist/execution/event.d.ts +26 -0
- package/dist/execution/event.js +29 -0
- package/dist/execution/event.js.map +1 -0
- package/dist/execution/next.d.ts +7 -0
- package/dist/execution/next.js +137 -0
- package/dist/execution/next.js.map +1 -0
- package/dist/execution/node.d.ts +4 -0
- package/dist/execution/node.js +194 -0
- package/dist/execution/node.js.map +1 -0
- package/dist/execution/phase.d.ts +5 -0
- package/dist/execution/phase.js +23 -0
- package/dist/execution/phase.js.map +1 -0
- package/dist/execution/process.d.ts +35 -0
- package/dist/execution/process.js +115 -0
- package/dist/execution/process.js.map +1 -0
- package/dist/input.d.ts +6 -0
- package/dist/input.js +4 -0
- package/dist/input.js.map +1 -0
- package/dist/logger.d.ts +12 -0
- package/dist/node/aggregatornode.d.ts +40 -0
- package/dist/node/aggregatornode.js +41 -0
- package/dist/node/aggregatornode.js.map +1 -0
- package/dist/node/node.d.ts +18 -0
- package/dist/node/node.js +80 -0
- package/dist/node/node.js.map +1 -0
- package/dist/node/phasenode.d.ts +49 -0
- package/dist/node/phasenode.js +37 -0
- package/dist/node/phasenode.js.map +1 -0
- package/dist/output.d.ts +6 -0
- package/dist/phase.d.ts +23 -0
- package/dist/phase.js +24 -0
- package/dist/phase.js.map +1 -0
- package/dist/process.d.ts +15 -0
- package/dist/process.js +106 -0
- package/dist/process.js.map +1 -0
- package/dist/transition/beginning.d.ts +19 -0
- package/dist/transition/beginning.js +31 -0
- package/dist/transition/beginning.js.map +1 -0
- package/dist/transition/connection.d.ts +55 -0
- package/dist/transition/connection.js +90 -0
- package/dist/transition/connection.js.map +1 -0
- package/dist/transition/decision.d.ts +20 -0
- package/dist/transition/decision.js +47 -0
- package/dist/transition/decision.js.map +1 -0
- package/dist/transition/next.d.ts +13 -0
- package/dist/transition/next.js +81 -0
- package/dist/transition/next.js.map +1 -0
- package/dist/transition/termination.d.ts +17 -0
- package/dist/transition/termination.js +50 -0
- package/dist/transition/termination.js.map +1 -0
- package/dist/transition/transition.d.ts +16 -0
- package/dist/transition/transition.js +72 -0
- package/dist/transition/transition.js.map +1 -0
- package/dist/util/general.d.ts +4 -0
- package/dist/util/general.js +6 -0
- package/dist/util/general.js.map +1 -0
- package/dist/utility/event/eventfilter.d.ts +7 -0
- package/dist/utility/event/eventfilter.js +15 -0
- package/dist/utility/event/eventfilter.js.map +1 -0
- package/dist/utility/event/filteredhandler.d.ts +13 -0
- package/dist/utility/event/filteredhandler.js +18 -0
- package/dist/utility/event/filteredhandler.js.map +1 -0
- package/dist/utility/event/logginghandler.d.ts +12 -0
- package/dist/xenocline.cjs +1362 -0
- package/dist/xenocline.cjs.map +1 -0
- package/dist/xenocline.d.ts +72 -0
- package/dist/xenocline.js +21 -0
- package/dist/xenocline.js.map +1 -0
- package/output/kodrdriv/260109-2305-commit-message.md +3 -0
- package/output/kodrdriv/260109-2307-release-notes.md +28 -0
- package/output/kodrdriv/260109-2318-commit-message.md +6 -0
- package/output/kodrdriv/260109-2321-release-notes.md +39 -0
- package/output/kodrdriv/RELEASE_NOTES.md +37 -0
- package/output/kodrdriv/RELEASE_TITLE.md +1 -0
- package/output/kodrdriv/agentic-reflection-commit-2026-01-10T07-05-39-771Z.md +52 -0
- package/output/kodrdriv/agentic-reflection-commit-2026-01-10T07-18-31-315Z.md +55 -0
- package/output/kodrdriv/agentic-reflection-release-2026-01-10T07-07-33-739Z.md +257 -0
- package/output/kodrdriv/agentic-reflection-release-2026-01-10T07-21-54-717Z.md +394 -0
- package/package.json +69 -0
- package/scripts/pre-commit-hook.sh +53 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aggregator.js","sources":["../../src/execution/aggregator.ts"],"sourcesContent":["import { Context } from '../context';\nimport { createAggregatorEvent, EventState } from '../event';\nimport { Input } from '../input';\nimport { AggregatorNode } from '../node/aggregatornode';\nimport { Output } from '../output';\nimport { dispatchEvent } from './event';\n\nexport class Deferred<T> {\n promise: Promise<T>;\n resolve!: (value: T | PromiseLike<T>) => void;\n reject!: (reason?: any) => void;\n\n constructor() {\n this.promise = new Promise<T>((resolve, reject) => {\n this.resolve = resolve;\n this.reject = reject;\n });\n }\n}\n\nexport interface AggregatorState {\n aggregatorDeferreds: Map<string, Deferred<Output>>;\n registerPendingAggregator: (nodeId: string) => Deferred<Output>;\n resolvePendingAggregator: (nodeId: string, output: Output) => void;\n getPendingAggregator: (nodeId: string) => Deferred<Output> | undefined;\n pendingAggregatorIds: () => string[];\n}\n\nexport function createAggregatorState(): AggregatorState {\n return {\n aggregatorDeferreds: new Map<string, Deferred<Output>>(),\n registerPendingAggregator(nodeId: string) {\n let deferred = this.aggregatorDeferreds.get(nodeId);\n if (!deferred) {\n deferred = new Deferred<Output>();\n this.aggregatorDeferreds.set(nodeId, deferred);\n }\n return deferred;\n },\n resolvePendingAggregator(nodeId: string, output: Output) {\n const deferred = this.aggregatorDeferreds.get(nodeId);\n if (deferred) {\n deferred.resolve(output);\n this.aggregatorDeferreds.delete(nodeId);\n }\n },\n getPendingAggregator(nodeId: string) {\n return this.aggregatorDeferreds.get(nodeId);\n },\n pendingAggregatorIds() {\n return Array.from(this.aggregatorDeferreds.keys());\n },\n };\n}\n\nexport async function executeAggregatorNode(\n nodeId: string,\n node: AggregatorNode,\n input: Input,\n state: AggregatorState & { context: Context, eventState: EventState<Context> }\n): Promise<Output> {\n\n dispatchEvent(\n state.eventState,\n createAggregatorEvent(nodeId, 'start', node.aggregator, { input }),\n state.context\n );\n\n let deferred = state.getPendingAggregator(nodeId);\n const aggregationResult = await node.aggregator.aggregate(input, state.context);\n\n dispatchEvent(state.eventState, createAggregatorEvent(nodeId, 'aggregate', node.aggregator, { input, result: aggregationResult }), state.context);\n\n if (aggregationResult.status === 'Ready') {\n const output = aggregationResult.output;\n\n dispatchEvent(state.eventState, createAggregatorEvent(nodeId, 'ready', node.aggregator, { output }), state.context);\n\n state.resolvePendingAggregator(nodeId, output);\n return output;\n }\n\n dispatchEvent(state.eventState, createAggregatorEvent(nodeId, 'defer', node.aggregator, { input, result: aggregationResult }), state.context);\n deferred = deferred ?? state.registerPendingAggregator(nodeId);\n return deferred.promise;\n}\n"],"names":["Deferred","promise","resolve","reject","Promise","createAggregatorState","aggregatorDeferreds","Map","registerPendingAggregator","nodeId","deferred","get","set","resolvePendingAggregator","output","delete","getPendingAggregator","pendingAggregatorIds","Array","from","keys","executeAggregatorNode","node","input","state","dispatchEvent","eventState","createAggregatorEvent","aggregator","context","aggregationResult","aggregate","result","status"],"mappings":";;;;;;;;;;;;;;;;AAOO,MAAMA,QAAAA,CAAAA;IAKT,WAAA,EAAc;AAJdC,QAAAA,gBAAAA,CAAAA,IAAAA,EAAAA,WAAAA,MAAAA,CAAAA;AACAC,QAAAA,gBAAAA,CAAAA,IAAAA,EAAAA,WAAAA,MAAAA,CAAAA;AACAC,QAAAA,gBAAAA,CAAAA,IAAAA,EAAAA,UAAAA,MAAAA,CAAAA;AAGI,QAAA,IAAI,CAACF,OAAO,GAAG,IAAIG,OAAAA,CAAW,CAACF,OAAAA,EAASC,MAAAA,GAAAA;YACpC,IAAI,CAACD,OAAO,GAAGA,OAAAA;YACf,IAAI,CAACC,MAAM,GAAGA,MAAAA;AAClB,QAAA,CAAA,CAAA;AACJ,IAAA;AACJ;AAUO,SAASE,qBAAAA,GAAAA;IACZ,OAAO;AACHC,QAAAA,mBAAAA,EAAqB,IAAIC,GAAAA,EAAAA;AACzBC,QAAAA,yBAAAA,CAAAA,CAA0BC,MAAc,EAAA;AACpC,YAAA,IAAIC,WAAW,IAAI,CAACJ,mBAAmB,CAACK,GAAG,CAACF,MAAAA,CAAAA;AAC5C,YAAA,IAAI,CAACC,QAAAA,EAAU;AACXA,gBAAAA,QAAAA,GAAW,IAAIV,QAAAA,EAAAA;AACf,gBAAA,IAAI,CAACM,mBAAmB,CAACM,GAAG,CAACH,MAAAA,EAAQC,QAAAA,CAAAA;AACzC,YAAA;YACA,OAAOA,QAAAA;AACX,QAAA,CAAA;QACAG,wBAAAA,CAAAA,CAAyBJ,MAAc,EAAEK,MAAc,EAAA;AACnD,YAAA,MAAMJ,WAAW,IAAI,CAACJ,mBAAmB,CAACK,GAAG,CAACF,MAAAA,CAAAA;AAC9C,YAAA,IAAIC,QAAAA,EAAU;AACVA,gBAAAA,QAAAA,CAASR,OAAO,CAACY,MAAAA,CAAAA;AACjB,gBAAA,IAAI,CAACR,mBAAmB,CAACS,MAAM,CAACN,MAAAA,CAAAA;AACpC,YAAA;AACJ,QAAA,CAAA;AACAO,QAAAA,oBAAAA,CAAAA,CAAqBP,MAAc,EAAA;AAC/B,YAAA,OAAO,IAAI,CAACH,mBAAmB,CAACK,GAAG,CAACF,MAAAA,CAAAA;AACxC,QAAA,CAAA;AACAQ,QAAAA,oBAAAA,CAAAA,GAAAA;AACI,YAAA,OAAOC,MAAMC,IAAI,CAAC,IAAI,CAACb,mBAAmB,CAACc,IAAI,EAAA,CAAA;AACnD,QAAA;AACJ,KAAA;AACJ;AAEO,eAAeC,sBAClBZ,MAAc,EACda,IAAoB,EACpBC,KAAY,EACZC,KAA8E,EAAA;IAG9EC,aAAAA,CACID,KAAAA,CAAME,UAAU,EAChBC,qBAAAA,CAAsBlB,QAAQ,OAAA,EAASa,IAAAA,CAAKM,UAAU,EAAE;AAAEL,QAAAA;AAAM,KAAA,CAAA,EAChEC,MAAMK,OAAO,CAAA;IAGjB,IAAInB,QAAAA,GAAWc,KAAAA,CAAMR,oBAAoB,CAACP,MAAAA,CAAAA;IAC1C,MAAMqB,iBAAAA,GAAoB,MAAMR,IAAAA,CAAKM,UAAU,CAACG,SAAS,CAACR,KAAAA,EAAOC,KAAAA,CAAMK,OAAO,CAAA;IAE9EJ,aAAAA,CAAcD,KAAAA,CAAME,UAAU,EAAEC,qBAAAA,CAAsBlB,QAAQ,WAAA,EAAaa,IAAAA,CAAKM,UAAU,EAAE;AAAEL,QAAAA,KAAAA;QAAOS,MAAAA,EAAQF;AAAkB,KAAA,CAAA,EAAIN,MAAMK,OAAO,CAAA;IAEhJ,IAAIC,iBAAAA,CAAkBG,MAAM,KAAK,OAAA,EAAS;QACtC,MAAMnB,MAAAA,GAASgB,kBAAkBhB,MAAM;QAEvCW,aAAAA,CAAcD,KAAAA,CAAME,UAAU,EAAEC,qBAAAA,CAAsBlB,QAAQ,OAAA,EAASa,IAAAA,CAAKM,UAAU,EAAE;AAAEd,YAAAA;AAAO,SAAA,CAAA,EAAIU,MAAMK,OAAO,CAAA;QAElHL,KAAAA,CAAMX,wBAAwB,CAACJ,MAAAA,EAAQK,MAAAA,CAAAA;QACvC,OAAOA,MAAAA;AACX,IAAA;IAEAW,aAAAA,CAAcD,KAAAA,CAAME,UAAU,EAAEC,qBAAAA,CAAsBlB,QAAQ,OAAA,EAASa,IAAAA,CAAKM,UAAU,EAAE;AAAEL,QAAAA,KAAAA;QAAOS,MAAAA,EAAQF;AAAkB,KAAA,CAAA,EAAIN,MAAMK,OAAO,CAAA;AAC5InB,IAAAA,QAAAA,GAAWA,QAAAA,KAAAA,IAAAA,IAAAA,QAAAA,KAAAA,MAAAA,GAAAA,QAAAA,GAAYc,KAAAA,CAAMhB,yBAAyB,CAACC,MAAAA,CAAAA;AACvD,IAAA,OAAOC,SAAST,OAAO;AAC3B;;;;"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Context } from '../context';
|
|
2
|
+
import { Event, EventHandler } from '../event';
|
|
3
|
+
/**
|
|
4
|
+
* Represents the state for managing event handlers.
|
|
5
|
+
* Event handlers are expected to handle the base `Event` type and perform
|
|
6
|
+
* specific event checking internally if needed (e.g., using type guards).
|
|
7
|
+
*/
|
|
8
|
+
export interface EventState<C extends Context> {
|
|
9
|
+
/** Readonly array of registered event handlers. */
|
|
10
|
+
readonly handlers: ReadonlyArray<EventHandler<Event, C>>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Creates an instance of EventState.
|
|
14
|
+
* @param handlers An optional array of event handlers to initialize the state with.
|
|
15
|
+
* These handlers should be of type `EventHandler<Event, C>`, meaning they
|
|
16
|
+
* are prepared to receive any event and filter internally if necessary.
|
|
17
|
+
* @returns A new, readonly EventState object.
|
|
18
|
+
*/
|
|
19
|
+
export declare const createEventState: <C extends Context>(handlers?: ReadonlyArray<EventHandler<Event, C>>) => Readonly<EventState<C>>;
|
|
20
|
+
/**
|
|
21
|
+
* Dispatches an event to all registered handlers.
|
|
22
|
+
* @param eventState The current event state containing the handlers.
|
|
23
|
+
* @param event The event to dispatch. This can be any specific event type that extends `Event`.
|
|
24
|
+
* @param context The current context to pass to the handlers.
|
|
25
|
+
*/
|
|
26
|
+
export declare const dispatchEvent: <E extends Event, C extends Context>(eventState: Readonly<EventState<C>>, event: E, context: C) => Promise<void>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates an instance of EventState.
|
|
3
|
+
* @param handlers An optional array of event handlers to initialize the state with.
|
|
4
|
+
* These handlers should be of type `EventHandler<Event, C>`, meaning they
|
|
5
|
+
* are prepared to receive any event and filter internally if necessary.
|
|
6
|
+
* @returns A new, readonly EventState object.
|
|
7
|
+
*/ const createEventState = (handlers)=>{
|
|
8
|
+
// Store a copy of the handlers array to ensure immutability of the provided array.
|
|
9
|
+
return {
|
|
10
|
+
handlers: handlers ? [
|
|
11
|
+
...handlers
|
|
12
|
+
] : []
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Dispatches an event to all registered handlers.
|
|
17
|
+
* @param eventState The current event state containing the handlers.
|
|
18
|
+
* @param event The event to dispatch. This can be any specific event type that extends `Event`.
|
|
19
|
+
* @param context The current context to pass to the handlers.
|
|
20
|
+
*/ const dispatchEvent = async (eventState, event, context)=>{
|
|
21
|
+
for (const handler of eventState.handlers){
|
|
22
|
+
// Each handler is EventHandler<Event, C>, so its `handle` method expects an `Event`.
|
|
23
|
+
// Since `E` extends `Event`, passing `event` (of type `E`) is type-safe.
|
|
24
|
+
await handler.handle(event, context);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export { createEventState, dispatchEvent };
|
|
29
|
+
//# sourceMappingURL=event.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event.js","sources":["../../src/execution/event.ts"],"sourcesContent":["import { Context } from '../context';\nimport { Event } from '../event'; // Assuming src/event.ts will export the base Event type\nimport { EventHandler } from '../event'; // Assuming src/event.ts will export EventHandler\n\n/**\n * Represents the state for managing event handlers.\n * Event handlers are expected to handle the base `Event` type and perform\n * specific event checking internally if needed (e.g., using type guards).\n */\nexport interface EventState<C extends Context> {\n /** Readonly array of registered event handlers. */\n readonly handlers: ReadonlyArray<EventHandler<Event, C>>;\n}\n\n/**\n * Creates an instance of EventState.\n * @param handlers An optional array of event handlers to initialize the state with.\n * These handlers should be of type `EventHandler<Event, C>`, meaning they\n * are prepared to receive any event and filter internally if necessary.\n * @returns A new, readonly EventState object.\n */\nexport const createEventState = <C extends Context>(\n handlers?: ReadonlyArray<EventHandler<Event, C>>\n): Readonly<EventState<C>> => {\n // Store a copy of the handlers array to ensure immutability of the provided array.\n return { handlers: handlers ? [...handlers] : [] };\n};\n\n/**\n * Dispatches an event to all registered handlers.\n * @param eventState The current event state containing the handlers.\n * @param event The event to dispatch. This can be any specific event type that extends `Event`.\n * @param context The current context to pass to the handlers.\n */\nexport const dispatchEvent = async <E extends Event, C extends Context>(\n eventState: Readonly<EventState<C>>,\n event: E,\n context: C\n): Promise<void> => {\n for (const handler of eventState.handlers) {\n // Each handler is EventHandler<Event, C>, so its `handle` method expects an `Event`.\n // Since `E` extends `Event`, passing `event` (of type `E`) is type-safe.\n await handler.handle(event, context);\n }\n};\n"],"names":["createEventState","handlers","dispatchEvent","eventState","event","context","handler","handle"],"mappings":"AAcA;;;;;;IAOO,MAAMA,gBAAAA,GAAmB,CAC5BC,QAAAA,GAAAA;;IAGA,OAAO;AAAEA,QAAAA,QAAAA,EAAUA,QAAAA,GAAW;AAAIA,YAAAA,GAAAA;AAAS,SAAA,GAAG;AAAG,KAAA;AACrD;AAEA;;;;;AAKC,IACM,MAAMC,aAAAA,GAAgB,OACzBC,YACAC,KAAAA,EACAC,OAAAA,GAAAA;AAEA,IAAA,KAAK,MAAMC,OAAAA,IAAWH,UAAAA,CAAWF,QAAQ,CAAE;;;QAGvC,MAAMK,OAAAA,CAAQC,MAAM,CAACH,KAAAA,EAAOC,OAAAA,CAAAA;AAChC,IAAA;AACJ;;;;"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ExecutionState } from './process';
|
|
2
|
+
import { Output } from '../output';
|
|
3
|
+
import { Connection } from '../transition/connection';
|
|
4
|
+
import { Decision } from '../transition/decision';
|
|
5
|
+
import { Termination } from '../transition/termination';
|
|
6
|
+
export declare function handleNextStep(nodeOutput: Output, nodeId: string, next: Termination | Connection[] | Decision[], // Can be Termination, Connection[], or Decision[] - will be narrowed down
|
|
7
|
+
state: ExecutionState): Promise<void>;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { executeNode } from './node.js';
|
|
2
|
+
import { isConnection } from '../transition/connection.js';
|
|
3
|
+
import { isDecision } from '../transition/decision.js';
|
|
4
|
+
import { isTermination } from '../transition/termination.js';
|
|
5
|
+
import { dispatchEvent } from './event.js';
|
|
6
|
+
import { createDecisionEvent, createConnectionEvent, createTerminationEvent } from '../event/transition.js';
|
|
7
|
+
|
|
8
|
+
// Helper function to handle the next step in the process
|
|
9
|
+
async function handleNextStep(nodeOutput, nodeId, next, state) {
|
|
10
|
+
//console.log('[_HANDLE_NEXT_STEP_START]', { nodeId, nodeOutput, nextType: next && next.constructor ? next.constructor.name : typeof next, next });
|
|
11
|
+
if (Array.isArray(next) && next.length > 0 && next.every(isDecision)) {
|
|
12
|
+
const decisions = next;
|
|
13
|
+
// console.log('[_HANDLE_NEXT_STEP_DECISIONS]', { nodeId, count: decisions.length, decisions });
|
|
14
|
+
for (const decision of decisions){
|
|
15
|
+
// console.log('[_HANDLE_NEXT_STEP_DECISION_PROCESSING]', { nodeId, decisionId: decision.id, decision });
|
|
16
|
+
await dispatchEvent(state.eventState, createDecisionEvent(nodeId, 'start', decision, {
|
|
17
|
+
output: nodeOutput
|
|
18
|
+
}), state.context);
|
|
19
|
+
try {
|
|
20
|
+
const decisionOutcome = await decision.decide(nodeOutput, state.context);
|
|
21
|
+
await dispatchEvent(state.eventState, createDecisionEvent(nodeId, 'decide', decision, {
|
|
22
|
+
output: nodeOutput,
|
|
23
|
+
result: decisionOutcome
|
|
24
|
+
}), state.context);
|
|
25
|
+
// console.log('[_HANDLE_NEXT_STEP_DECISION_OUTCOME]', { nodeId, decisionId: decision.id, decisionOutcome });
|
|
26
|
+
await handleNextStep(nodeOutput, decision.id, decisionOutcome, state); // outcome processed, decision.id is context for next step if it's an error source. The original nodeId is implicitly the source of this decision.
|
|
27
|
+
await dispatchEvent(state.eventState, createDecisionEvent(nodeId, 'end', decision), state.context);
|
|
28
|
+
} catch (decisionError) {
|
|
29
|
+
const errorMessage = `Decision error on '${decision.id}' from node '${nodeId}': ${decisionError.message}`;
|
|
30
|
+
// eslint-disable-next-line no-console
|
|
31
|
+
console.error(`[_HANDLE_NEXT_STEP_DECISION_ERROR]`, {
|
|
32
|
+
error: errorMessage,
|
|
33
|
+
decisionError,
|
|
34
|
+
decisionId: decision.id,
|
|
35
|
+
sourceNodeId: nodeId
|
|
36
|
+
});
|
|
37
|
+
state.errors.push({
|
|
38
|
+
nodeId: decision.id,
|
|
39
|
+
message: errorMessage,
|
|
40
|
+
details: {
|
|
41
|
+
sourceNodeId: nodeId,
|
|
42
|
+
originalError: decisionError.message
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
// Note: Decision errors are logged but do not halt the process.
|
|
46
|
+
// This allows other parallel decisions to continue executing.
|
|
47
|
+
// If you need decision errors to halt execution, consider throwing here
|
|
48
|
+
// or checking state.errors after process completion.
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
} else if (Array.isArray(next) && next.length > 0 && next.every(isConnection)) {
|
|
52
|
+
//console.log('[_HANDLE_NEXT_STEP_CONNECTIONS]', { nodeId, count: next.length, connections: next });
|
|
53
|
+
const connections = next;
|
|
54
|
+
const nextPhasePromises = [];
|
|
55
|
+
for (const connection of connections){
|
|
56
|
+
let nextInput = nodeOutput;
|
|
57
|
+
let nextContext = state.context;
|
|
58
|
+
await dispatchEvent(state.eventState, createConnectionEvent(nodeId, 'start', connection, {
|
|
59
|
+
input: nextInput
|
|
60
|
+
}), state.context);
|
|
61
|
+
if (connection.transform) {
|
|
62
|
+
//console.log('[_HANDLE_NEXT_STEP_CONNECTION_TRANSFORM_START]', { nodeId, targetNodeId: connection.targetNodeId });
|
|
63
|
+
try {
|
|
64
|
+
const context = state.context;
|
|
65
|
+
[nextInput, nextContext] = await connection.transform(nodeOutput, context);
|
|
66
|
+
await dispatchEvent(state.eventState, createConnectionEvent(nodeId, 'transform', connection, {
|
|
67
|
+
input: nextInput,
|
|
68
|
+
output: nodeOutput,
|
|
69
|
+
context: nextContext
|
|
70
|
+
}), state.context);
|
|
71
|
+
state.context = nextContext;
|
|
72
|
+
//console.log('[_HANDLE_NEXT_STEP_CONNECTION_TRANSFORM_SUCCESS]', { nodeId, targetNodeId: connection.targetNodeId, nextInput, nextContext });
|
|
73
|
+
} catch (transformError) {
|
|
74
|
+
const errorMessage = `Transform error on connection '${connection.id}' from node '${nodeId}' to '${connection.targetNodeId}': ${transformError.message}`;
|
|
75
|
+
// eslint-disable-next-line no-console
|
|
76
|
+
console.error(`[_HANDLE_NEXT_STEP_CONNECTION_TRANSFORM_ERROR]`, {
|
|
77
|
+
error: errorMessage,
|
|
78
|
+
transformError,
|
|
79
|
+
connectionId: connection.id,
|
|
80
|
+
sourceNodeId: nodeId,
|
|
81
|
+
targetNodeId: connection.targetNodeId
|
|
82
|
+
});
|
|
83
|
+
// Store error with connection ID for better traceability
|
|
84
|
+
state.errors.push({
|
|
85
|
+
nodeId: connection.id,
|
|
86
|
+
message: errorMessage,
|
|
87
|
+
details: {
|
|
88
|
+
sourceNodeId: nodeId,
|
|
89
|
+
targetNodeId: connection.targetNodeId,
|
|
90
|
+
originalError: transformError.message
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//console.log('[_HANDLE_NEXT_STEP_CONNECTION_EXECUTE_TARGET]', { nodeId, targetNodeId: connection.targetNodeId, nextInput });
|
|
97
|
+
nextPhasePromises.push(executeNode(connection.targetNodeId, nextInput, state));
|
|
98
|
+
await dispatchEvent(state.eventState, createConnectionEvent(nodeId, 'end', connection), state.context);
|
|
99
|
+
}
|
|
100
|
+
// Optional: await Promise.all(nextPhasePromises); // Current design relies on executeProcess waiting on activeExecutions
|
|
101
|
+
//console.log('[_HANDLE_NEXT_STEP_CONNECTIONS_PROMISES_PUSHED]', { nodeId, count: nextPhasePromises.length });
|
|
102
|
+
} else if (isTermination(next)) {
|
|
103
|
+
//console.log('[_HANDLE_NEXT_STEP_TERMINATION]', { nodeId, termination: next });
|
|
104
|
+
const termination = next;
|
|
105
|
+
await dispatchEvent(state.eventState, createTerminationEvent(nodeId, 'start', termination, {
|
|
106
|
+
output: nodeOutput
|
|
107
|
+
}), state.context);
|
|
108
|
+
const result = nodeOutput;
|
|
109
|
+
if (termination.terminate) {
|
|
110
|
+
//console.log('[_HANDLE_NEXT_STEP_TERMINATION_CALLING_TERMINATE_FN]', { nodeId, terminationId: termination.id });
|
|
111
|
+
await termination.terminate(nodeOutput, state.context);
|
|
112
|
+
await dispatchEvent(state.eventState, createTerminationEvent(nodeId, 'terminate', termination, {
|
|
113
|
+
output: nodeOutput
|
|
114
|
+
}), state.context);
|
|
115
|
+
}
|
|
116
|
+
state.results[termination.id] = result;
|
|
117
|
+
} else if (Array.isArray(next) && next.length === 0) {
|
|
118
|
+
// Empty array from a Decision means no path should be taken from this node.
|
|
119
|
+
// This is treated as an implicit termination, storing the result with a generated key.
|
|
120
|
+
// Note: This behavior means a Decision can dynamically terminate a process path.
|
|
121
|
+
const result = nodeOutput;
|
|
122
|
+
const implicitTerminationId = `${nodeId}_implicit_end`;
|
|
123
|
+
state.results[implicitTerminationId] = result;
|
|
124
|
+
// eslint-disable-next-line no-console
|
|
125
|
+
console.warn(`[_HANDLE_NEXT_STEP_IMPLICIT_TERMINATION] Node ${nodeId} received empty next array, treating as implicit termination with id: ${implicitTerminationId}`);
|
|
126
|
+
} else {
|
|
127
|
+
// If there is no next (e.g. next is undefined or null after a decision), or it's an unhandled type.
|
|
128
|
+
// Consider this an end state and store the result with the nodeId
|
|
129
|
+
//console.log('[_HANDLE_NEXT_STEP_NO_NEXT_OR_UNHANDLED]', { nodeId, next, nodeOutput });
|
|
130
|
+
const result = nodeOutput;
|
|
131
|
+
state.results[nodeId] = result;
|
|
132
|
+
}
|
|
133
|
+
//console.log('[_HANDLE_NEXT_STEP_END]', { nodeId });
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export { handleNextStep };
|
|
137
|
+
//# sourceMappingURL=next.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"next.js","sources":["../../src/execution/next.ts"],"sourcesContent":["import { executeNode } from './node';\nimport { ExecutionState } from './process';\nimport { Context } from '../context';\nimport { Input } from '../input';\nimport { Output } from '../output';\nimport { Connection, isConnection } from '../transition/connection';\nimport { Decision, isDecision } from '../transition/decision';\nimport { isTermination, Termination } from '../transition/termination';\nimport { dispatchEvent } from './event';\nimport { createConnectionEvent, createDecisionEvent, createTerminationEvent } from '../event';\n\n// Helper function to handle the next step in the process\nexport async function handleNextStep(\n nodeOutput: Output,\n nodeId: string,\n next: Termination | Connection[] | Decision[], // Can be Termination, Connection[], or Decision[] - will be narrowed down\n state: ExecutionState\n): Promise<void> {\n\n //console.log('[_HANDLE_NEXT_STEP_START]', { nodeId, nodeOutput, nextType: next && next.constructor ? next.constructor.name : typeof next, next });\n\n if (Array.isArray(next) && next.length > 0 && next.every(isDecision)) {\n const decisions = next as Decision<Output, Context>[];\n // console.log('[_HANDLE_NEXT_STEP_DECISIONS]', { nodeId, count: decisions.length, decisions });\n\n for (const decision of decisions) {\n // console.log('[_HANDLE_NEXT_STEP_DECISION_PROCESSING]', { nodeId, decisionId: decision.id, decision });\n await dispatchEvent(\n state.eventState,\n createDecisionEvent(nodeId, 'start', decision, { output: nodeOutput }),\n state.context\n );\n try {\n const decisionOutcome = await decision.decide(nodeOutput, state.context);\n await dispatchEvent(\n state.eventState,\n createDecisionEvent(nodeId, 'decide', decision, { output: nodeOutput, result: decisionOutcome }),\n state.context\n );\n // console.log('[_HANDLE_NEXT_STEP_DECISION_OUTCOME]', { nodeId, decisionId: decision.id, decisionOutcome });\n await handleNextStep(nodeOutput, decision.id, decisionOutcome, state); // outcome processed, decision.id is context for next step if it's an error source. The original nodeId is implicitly the source of this decision.\n await dispatchEvent(\n state.eventState,\n createDecisionEvent(nodeId, 'end', decision), // Fire 'end' event after successful processing\n state.context\n );\n } catch (decisionError: any) {\n const errorMessage = `Decision error on '${decision.id}' from node '${nodeId}': ${decisionError.message}`;\n // eslint-disable-next-line no-console\n console.error(`[_HANDLE_NEXT_STEP_DECISION_ERROR]`, {\n error: errorMessage,\n decisionError,\n decisionId: decision.id,\n sourceNodeId: nodeId\n });\n state.errors.push({\n nodeId: decision.id,\n message: errorMessage,\n details: { sourceNodeId: nodeId, originalError: decisionError.message }\n });\n // Note: Decision errors are logged but do not halt the process.\n // This allows other parallel decisions to continue executing.\n // If you need decision errors to halt execution, consider throwing here\n // or checking state.errors after process completion.\n }\n }\n } else if (Array.isArray(next) && next.length > 0 && next.every(isConnection)) {\n\n //console.log('[_HANDLE_NEXT_STEP_CONNECTIONS]', { nodeId, count: next.length, connections: next });\n const connections = next as Connection<Output, Context>[];\n const nextPhasePromises: Promise<Output>[] = [];\n for (const connection of connections) {\n\n let nextInput = nodeOutput as Input;\n let nextContext = state.context;\n\n await dispatchEvent(\n state.eventState,\n createConnectionEvent(nodeId, 'start', connection, { input: nextInput }),\n state.context\n );\n\n if (connection.transform) {\n\n //console.log('[_HANDLE_NEXT_STEP_CONNECTION_TRANSFORM_START]', { nodeId, targetNodeId: connection.targetNodeId });\n try {\n const context = state.context;\n [nextInput, nextContext] = await connection.transform(nodeOutput, context);\n await dispatchEvent(\n state.eventState,\n createConnectionEvent(nodeId, 'transform', connection, { input: nextInput, output: nodeOutput, context: nextContext }),\n state.context\n );\n state.context = nextContext;\n\n //console.log('[_HANDLE_NEXT_STEP_CONNECTION_TRANSFORM_SUCCESS]', { nodeId, targetNodeId: connection.targetNodeId, nextInput, nextContext });\n } catch (transformError: any) {\n const errorMessage = `Transform error on connection '${connection.id}' from node '${nodeId}' to '${connection.targetNodeId}': ${transformError.message}`;\n // eslint-disable-next-line no-console\n console.error(`[_HANDLE_NEXT_STEP_CONNECTION_TRANSFORM_ERROR]`, {\n error: errorMessage,\n transformError,\n connectionId: connection.id,\n sourceNodeId: nodeId,\n targetNodeId: connection.targetNodeId\n });\n // Store error with connection ID for better traceability\n state.errors.push({\n nodeId: connection.id,\n message: errorMessage,\n details: { sourceNodeId: nodeId, targetNodeId: connection.targetNodeId, originalError: transformError.message }\n });\n // Skip this connection path - other parallel connections will still execute\n // This allows partial success in fan-out scenarios\n continue;\n }\n }\n\n //console.log('[_HANDLE_NEXT_STEP_CONNECTION_EXECUTE_TARGET]', { nodeId, targetNodeId: connection.targetNodeId, nextInput });\n nextPhasePromises.push(executeNode(connection.targetNodeId, nextInput, state));\n await dispatchEvent(\n state.eventState,\n createConnectionEvent(nodeId, 'end', connection), // Fire 'end' event after initiating next step\n state.context\n );\n }\n // Optional: await Promise.all(nextPhasePromises); // Current design relies on executeProcess waiting on activeExecutions\n\n //console.log('[_HANDLE_NEXT_STEP_CONNECTIONS_PROMISES_PUSHED]', { nodeId, count: nextPhasePromises.length });\n } else if (isTermination(next)) {\n\n //console.log('[_HANDLE_NEXT_STEP_TERMINATION]', { nodeId, termination: next });\n const termination = next as Termination<Output, Context>;\n await dispatchEvent(\n state.eventState,\n createTerminationEvent(nodeId, 'start', termination, { output: nodeOutput }),\n state.context\n );\n const result: Output = nodeOutput;\n if (termination.terminate) {\n\n //console.log('[_HANDLE_NEXT_STEP_TERMINATION_CALLING_TERMINATE_FN]', { nodeId, terminationId: termination.id });\n await termination.terminate(nodeOutput, state.context);\n await dispatchEvent(\n state.eventState,\n createTerminationEvent(nodeId, 'terminate', termination, { output: nodeOutput }),\n state.context\n );\n }\n\n state.results[termination.id] = result;\n } else if (Array.isArray(next) && next.length === 0) {\n // Empty array from a Decision means no path should be taken from this node.\n // This is treated as an implicit termination, storing the result with a generated key.\n // Note: This behavior means a Decision can dynamically terminate a process path.\n\n const result: Output = nodeOutput;\n const implicitTerminationId = `${nodeId}_implicit_end`;\n state.results[implicitTerminationId] = result;\n\n // eslint-disable-next-line no-console\n console.warn(`[_HANDLE_NEXT_STEP_IMPLICIT_TERMINATION] Node ${nodeId} received empty next array, treating as implicit termination with id: ${implicitTerminationId}`);\n } else {\n // If there is no next (e.g. next is undefined or null after a decision), or it's an unhandled type.\n // Consider this an end state and store the result with the nodeId\n\n //console.log('[_HANDLE_NEXT_STEP_NO_NEXT_OR_UNHANDLED]', { nodeId, next, nodeOutput });\n const result: Output = nodeOutput;\n state.results[nodeId] = result;\n }\n\n //console.log('[_HANDLE_NEXT_STEP_END]', { nodeId });\n}\n"],"names":["handleNextStep","nodeOutput","nodeId","next","state","Array","isArray","length","every","isDecision","decisions","decision","dispatchEvent","eventState","createDecisionEvent","output","context","decisionOutcome","decide","result","id","decisionError","errorMessage","message","console","error","decisionId","sourceNodeId","errors","push","details","originalError","isConnection","connections","nextPhasePromises","connection","nextInput","nextContext","createConnectionEvent","input","transform","transformError","targetNodeId","connectionId","executeNode","isTermination","termination","createTerminationEvent","terminate","results","implicitTerminationId","warn"],"mappings":";;;;;;;AAWA;AACO,eAAeA,eAClBC,UAAkB,EAClBC,MAAc,EACdC,IAA6C,EAC7CC,KAAqB,EAAA;;IAKrB,IAAIC,KAAAA,CAAMC,OAAO,CAACH,IAAAA,CAAAA,IAASA,IAAAA,CAAKI,MAAM,GAAG,CAAA,IAAKJ,IAAAA,CAAKK,KAAK,CAACC,UAAAA,CAAAA,EAAa;AAClE,QAAA,MAAMC,SAAAA,GAAYP,IAAAA;;QAGlB,KAAK,MAAMQ,YAAYD,SAAAA,CAAW;;AAE9B,YAAA,MAAME,cACFR,KAAAA,CAAMS,UAAU,EAChBC,mBAAAA,CAAoBZ,MAAAA,EAAQ,SAASS,QAAAA,EAAU;gBAAEI,MAAAA,EAAQd;AAAW,aAAA,CAAA,EACpEG,MAAMY,OAAO,CAAA;YAEjB,IAAI;AACA,gBAAA,MAAMC,kBAAkB,MAAMN,QAAAA,CAASO,MAAM,CAACjB,UAAAA,EAAYG,MAAMY,OAAO,CAAA;AACvE,gBAAA,MAAMJ,cACFR,KAAAA,CAAMS,UAAU,EAChBC,mBAAAA,CAAoBZ,MAAAA,EAAQ,UAAUS,QAAAA,EAAU;oBAAEI,MAAAA,EAAQd,UAAAA;oBAAYkB,MAAAA,EAAQF;AAAgB,iBAAA,CAAA,EAC9Fb,MAAMY,OAAO,CAAA;;AAGjB,gBAAA,MAAMhB,eAAeC,UAAAA,EAAYU,QAAAA,CAASS,EAAE,EAAEH,eAAAA,EAAiBb;gBAC/D,MAAMQ,aAAAA,CACFR,MAAMS,UAAU,EAChBC,oBAAoBZ,MAAAA,EAAQ,KAAA,EAAOS,QAAAA,CAAAA,EACnCP,KAAAA,CAAMY,OAAO,CAAA;AAErB,YAAA,CAAA,CAAE,OAAOK,aAAAA,EAAoB;AACzB,gBAAA,MAAMC,YAAAA,GAAe,CAAC,mBAAmB,EAAEX,SAASS,EAAE,CAAC,aAAa,EAAElB,MAAAA,CAAO,GAAG,EAAEmB,aAAAA,CAAcE,OAAO,CAAA,CAAE;;AAEzGC,gBAAAA,OAAAA,CAAQC,KAAK,CAAC,CAAC,kCAAkC,CAAC,EAAE;oBAChDA,KAAAA,EAAOH,YAAAA;AACPD,oBAAAA,aAAAA;AACAK,oBAAAA,UAAAA,EAAYf,SAASS,EAAE;oBACvBO,YAAAA,EAAczB;AAClB,iBAAA,CAAA;gBACAE,KAAAA,CAAMwB,MAAM,CAACC,IAAI,CAAC;AACd3B,oBAAAA,MAAAA,EAAQS,SAASS,EAAE;oBACnBG,OAAAA,EAASD,YAAAA;oBACTQ,OAAAA,EAAS;wBAAEH,YAAAA,EAAczB,MAAAA;AAAQ6B,wBAAAA,aAAAA,EAAeV,cAAcE;AAAQ;AAC1E,iBAAA,CAAA;;;;;AAKJ,YAAA;AACJ,QAAA;AACJ,IAAA,CAAA,MAAO,IAAIlB,KAAAA,CAAMC,OAAO,CAACH,IAAAA,CAAAA,IAASA,IAAAA,CAAKI,MAAM,GAAG,CAAA,IAAKJ,IAAAA,CAAKK,KAAK,CAACwB,YAAAA,CAAAA,EAAe;;AAG3E,QAAA,MAAMC,WAAAA,GAAc9B,IAAAA;AACpB,QAAA,MAAM+B,oBAAuC,EAAE;QAC/C,KAAK,MAAMC,cAAcF,WAAAA,CAAa;AAElC,YAAA,IAAIG,SAAAA,GAAYnC,UAAAA;YAChB,IAAIoC,WAAAA,GAAcjC,MAAMY,OAAO;AAE/B,YAAA,MAAMJ,cACFR,KAAAA,CAAMS,UAAU,EAChByB,qBAAAA,CAAsBpC,MAAAA,EAAQ,SAASiC,UAAAA,EAAY;gBAAEI,KAAAA,EAAOH;AAAU,aAAA,CAAA,EACtEhC,MAAMY,OAAO,CAAA;YAGjB,IAAImB,UAAAA,CAAWK,SAAS,EAAE;;gBAGtB,IAAI;oBACA,MAAMxB,OAAAA,GAAUZ,MAAMY,OAAO;AAC7B,oBAAA,CAACoB,WAAWC,WAAAA,CAAY,GAAG,MAAMF,UAAAA,CAAWK,SAAS,CAACvC,UAAAA,EAAYe,OAAAA,CAAAA;AAClE,oBAAA,MAAMJ,cACFR,KAAAA,CAAMS,UAAU,EAChByB,qBAAAA,CAAsBpC,MAAAA,EAAQ,aAAaiC,UAAAA,EAAY;wBAAEI,KAAAA,EAAOH,SAAAA;wBAAWrB,MAAAA,EAAQd,UAAAA;wBAAYe,OAAAA,EAASqB;AAAY,qBAAA,CAAA,EACpHjC,MAAMY,OAAO,CAAA;AAEjBZ,oBAAAA,KAAAA,CAAMY,OAAO,GAAGqB,WAAAA;;AAGpB,gBAAA,CAAA,CAAE,OAAOI,cAAAA,EAAqB;AAC1B,oBAAA,MAAMnB,eAAe,CAAC,+BAA+B,EAAEa,UAAAA,CAAWf,EAAE,CAAC,aAAa,EAAElB,OAAO,MAAM,EAAEiC,WAAWO,YAAY,CAAC,GAAG,EAAED,cAAAA,CAAelB,OAAO,CAAA,CAAE;;AAExJC,oBAAAA,OAAAA,CAAQC,KAAK,CAAC,CAAC,8CAA8C,CAAC,EAAE;wBAC5DA,KAAAA,EAAOH,YAAAA;AACPmB,wBAAAA,cAAAA;AACAE,wBAAAA,YAAAA,EAAcR,WAAWf,EAAE;wBAC3BO,YAAAA,EAAczB,MAAAA;AACdwC,wBAAAA,YAAAA,EAAcP,WAAWO;AAC7B,qBAAA,CAAA;;oBAEAtC,KAAAA,CAAMwB,MAAM,CAACC,IAAI,CAAC;AACd3B,wBAAAA,MAAAA,EAAQiC,WAAWf,EAAE;wBACrBG,OAAAA,EAASD,YAAAA;wBACTQ,OAAAA,EAAS;4BAAEH,YAAAA,EAAczB,MAAAA;AAAQwC,4BAAAA,YAAAA,EAAcP,WAAWO,YAAY;AAAEX,4BAAAA,aAAAA,EAAeU,eAAelB;AAAQ;AAClH,qBAAA,CAAA;AAGA,oBAAA;AACJ,gBAAA;AACJ,YAAA;;AAGAW,YAAAA,iBAAAA,CAAkBL,IAAI,CAACe,WAAAA,CAAYT,UAAAA,CAAWO,YAAY,EAAEN,SAAAA,EAAWhC,KAAAA,CAAAA,CAAAA;YACvE,MAAMQ,aAAAA,CACFR,MAAMS,UAAU,EAChByB,sBAAsBpC,MAAAA,EAAQ,KAAA,EAAOiC,UAAAA,CAAAA,EACrC/B,KAAAA,CAAMY,OAAO,CAAA;AAErB,QAAA;;;IAIJ,CAAA,MAAO,IAAI6B,cAAc1C,IAAAA,CAAAA,EAAO;;AAG5B,QAAA,MAAM2C,WAAAA,GAAc3C,IAAAA;AACpB,QAAA,MAAMS,cACFR,KAAAA,CAAMS,UAAU,EAChBkC,sBAAAA,CAAuB7C,MAAAA,EAAQ,SAAS4C,WAAAA,EAAa;YAAE/B,MAAAA,EAAQd;AAAW,SAAA,CAAA,EAC1EG,MAAMY,OAAO,CAAA;AAEjB,QAAA,MAAMG,MAAAA,GAAiBlB,UAAAA;QACvB,IAAI6C,WAAAA,CAAYE,SAAS,EAAE;;AAGvB,YAAA,MAAMF,WAAAA,CAAYE,SAAS,CAAC/C,UAAAA,EAAYG,MAAMY,OAAO,CAAA;AACrD,YAAA,MAAMJ,cACFR,KAAAA,CAAMS,UAAU,EAChBkC,sBAAAA,CAAuB7C,MAAAA,EAAQ,aAAa4C,WAAAA,EAAa;gBAAE/B,MAAAA,EAAQd;AAAW,aAAA,CAAA,EAC9EG,MAAMY,OAAO,CAAA;AAErB,QAAA;AAEAZ,QAAAA,KAAAA,CAAM6C,OAAO,CAACH,WAAAA,CAAY1B,EAAE,CAAC,GAAGD,MAAAA;IACpC,CAAA,MAAO,IAAId,MAAMC,OAAO,CAACH,SAASA,IAAAA,CAAKI,MAAM,KAAK,CAAA,EAAG;;;;AAKjD,QAAA,MAAMY,MAAAA,GAAiBlB,UAAAA;AACvB,QAAA,MAAMiD,qBAAAA,GAAwB,CAAA,EAAGhD,MAAAA,CAAO,aAAa,CAAC;QACtDE,KAAAA,CAAM6C,OAAO,CAACC,qBAAAA,CAAsB,GAAG/B,MAAAA;;QAGvCK,OAAAA,CAAQ2B,IAAI,CAAC,CAAC,8CAA8C,EAAEjD,MAAAA,CAAO,sEAAsE,EAAEgD,qBAAAA,CAAAA,CAAuB,CAAA;IACxK,CAAA,MAAO;;;;AAKH,QAAA,MAAM/B,MAAAA,GAAiBlB,UAAAA;QACvBG,KAAAA,CAAM6C,OAAO,CAAC/C,MAAAA,CAAO,GAAGiB,MAAAA;AAC5B,IAAA;AAEA;AACJ;;;;"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { createAggregatorNodeEvent, createPhaseNodeEvent } from '../event/node.js';
|
|
2
|
+
import { createDecisionEvent } from '../event/transition.js';
|
|
3
|
+
import { isAggregatorNode } from '../node/aggregatornode.js';
|
|
4
|
+
import { isPhaseNode } from '../node/phasenode.js';
|
|
5
|
+
import { isDecision } from '../transition/decision.js';
|
|
6
|
+
import { executeAggregatorNode } from './aggregator.js';
|
|
7
|
+
import { dispatchEvent } from './event.js';
|
|
8
|
+
import { handleNextStep } from './next.js';
|
|
9
|
+
import { executePhase } from './phase.js';
|
|
10
|
+
|
|
11
|
+
async function executeNode(nodeId, input, state) {
|
|
12
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_START]', { nodeId, input, phaseResultsKeys: Object.keys(state.phaseResults), activeExecutionsKeys: Array.from(state.activeExecutions.keys()), aggregatorDeferredsKeys: Array.from(state.aggregatorDeferreds.keys()) });
|
|
13
|
+
// 1. Check if result is already cached in phaseResults (final output, node fully completed)
|
|
14
|
+
if (state.phaseResults[nodeId]) {
|
|
15
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_CACHE_HIT_PHASERESULTS]', { nodeId, result: state.phaseResults[nodeId] });
|
|
16
|
+
return state.phaseResults[nodeId];
|
|
17
|
+
}
|
|
18
|
+
const node = state.process.phases[nodeId];
|
|
19
|
+
if (!node) {
|
|
20
|
+
const error = new Error(`Node with ID "${nodeId}" not found.`);
|
|
21
|
+
//console.error('[EXECUTE_NODE_RECURSIVE_NODE_NOT_FOUND]', { nodeId, error });
|
|
22
|
+
state.errors.push({
|
|
23
|
+
nodeId,
|
|
24
|
+
message: error.message
|
|
25
|
+
});
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_NODE_FOUND]', { nodeId, nodeType: node.constructor.name, node });
|
|
29
|
+
// 2. Handle active/pending executions
|
|
30
|
+
// If it's an aggregator that has a deferred promise, it means it's pending.
|
|
31
|
+
// We need to re-evaluate it with the current input. The IIFE below will handle this.
|
|
32
|
+
if (state.activeExecutions.has(nodeId) && !isAggregatorNode(node)) {
|
|
33
|
+
// For non-aggregators, if already active, return the promise.
|
|
34
|
+
// Aggregators will fall through to the IIFE to allow input processing.
|
|
35
|
+
// The IIFE itself handles returning a shared deferred promise if needed.
|
|
36
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_ACTIVE_EXECUTION_HIT_NON_AGGREGATOR]', { nodeId });
|
|
37
|
+
return state.activeExecutions.get(nodeId);
|
|
38
|
+
}
|
|
39
|
+
// If it IS an aggregator and state.activeExecutions.has(nodeId),
|
|
40
|
+
// it means its deferred.promise might be in activeExecutions from a previous input that made it pending.
|
|
41
|
+
// The IIFE logic below will correctly retrieve this deferred (if it exists and is still relevant)
|
|
42
|
+
// from state.aggregatorDeferreds.get(nodeId) and use its promise, or process the input.
|
|
43
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_CONTINUING_TO_EXECUTION_LOGIC]', { nodeId, isActive: state.activeExecutions.has(nodeId), isAggregator: isAggregatorNode(node), hasDeferred: state.aggregatorDeferreds.has(nodeId) });
|
|
44
|
+
// If it's an aggregator and it's pending (has a deferred), we fall through to re-execute its logic within the IIFE.
|
|
45
|
+
// If it's the first call to any node, we fall through.
|
|
46
|
+
// 3. Mark as active and execute (or re-evaluate pending aggregator)
|
|
47
|
+
const executionPromise = (async ()=>{
|
|
48
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_IIFE_START]', { nodeId, input });
|
|
49
|
+
try {
|
|
50
|
+
let output;
|
|
51
|
+
if (isAggregatorNode(node)) {
|
|
52
|
+
dispatchEvent(state.eventState, createAggregatorNodeEvent(nodeId, 'start', node, {
|
|
53
|
+
input
|
|
54
|
+
}), state.context);
|
|
55
|
+
output = await executeAggregatorNode(nodeId, node, input, state);
|
|
56
|
+
} else if (isPhaseNode(node)) {
|
|
57
|
+
dispatchEvent(state.eventState, createPhaseNodeEvent(nodeId, 'start', node, {
|
|
58
|
+
input
|
|
59
|
+
}), state.context);
|
|
60
|
+
if (node.prepare) {
|
|
61
|
+
const [preparedInput, preparedContext] = await node.prepare(input, state.context);
|
|
62
|
+
input = preparedInput;
|
|
63
|
+
state.context = preparedContext;
|
|
64
|
+
}
|
|
65
|
+
dispatchEvent(state.eventState, createPhaseNodeEvent(nodeId, 'prepared', node, {
|
|
66
|
+
input
|
|
67
|
+
}), state.context);
|
|
68
|
+
output = await executePhase(nodeId, node, input, state);
|
|
69
|
+
if (node.process) {
|
|
70
|
+
const [processedOutput, processedContext] = await node.process(output, state.context);
|
|
71
|
+
output = processedOutput;
|
|
72
|
+
state.context = processedContext;
|
|
73
|
+
}
|
|
74
|
+
dispatchEvent(state.eventState, createPhaseNodeEvent(nodeId, 'processed', node, {
|
|
75
|
+
input,
|
|
76
|
+
output
|
|
77
|
+
}), state.context);
|
|
78
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_PHASE_NODE_EXECUTE_END]', { nodeId, output });
|
|
79
|
+
} else {
|
|
80
|
+
const error = new Error(`Unknown or invalid node type for ID "${nodeId}". Expected PhaseNode or AggregatorNode.`);
|
|
81
|
+
//console.error('[EXECUTE_NODE_RECURSIVE_UNKNOWN_NODE_TYPE]', { nodeId, node, error });
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
state.phaseResults[nodeId] = output; // Set final output once ready/executed
|
|
85
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_PHASE_RESULT_CACHED]', { nodeId, output });
|
|
86
|
+
// 4. Handle next step
|
|
87
|
+
if (node.next) {
|
|
88
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_HANDLING_NEXT_STEP]', { nodeId, nextType: node.next.constructor.name, next: node.next });
|
|
89
|
+
if (Array.isArray(node.next) && node.next.length > 0 && node.next.every(isDecision)) {
|
|
90
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_DECISIONS_FOUND]', { nodeId, count: node.next.length, decisions: node.next });
|
|
91
|
+
const decisions = node.next;
|
|
92
|
+
const decisionExecutionPromises = [];
|
|
93
|
+
for (const decision of decisions){
|
|
94
|
+
dispatchEvent(state.eventState, createDecisionEvent(nodeId, 'start', decision, {
|
|
95
|
+
output
|
|
96
|
+
}), state.context);
|
|
97
|
+
const decisionPromise = (async ()=>{
|
|
98
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_DECISION_EXECUTE_START]', { nodeId, decisionId: decision.id, output });
|
|
99
|
+
try {
|
|
100
|
+
const decisionOutcome = await decision.decide(output, state.context);
|
|
101
|
+
dispatchEvent(state.eventState, createDecisionEvent(nodeId, 'decide', decision, {
|
|
102
|
+
output,
|
|
103
|
+
result: decisionOutcome
|
|
104
|
+
}), state.context);
|
|
105
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_DECISION_OUTCOME]', { nodeId, decisionId: decision.id, decisionOutcome });
|
|
106
|
+
await handleNextStep(output, decision.id, decisionOutcome, state);
|
|
107
|
+
dispatchEvent(state.eventState, createDecisionEvent(nodeId, 'end', decision), state.context);
|
|
108
|
+
} catch (decisionError) {
|
|
109
|
+
const errorMessage = `Decision error on '${decision.id}' for node '${nodeId}': ${decisionError.message}`;
|
|
110
|
+
// eslint-disable-next-line no-console
|
|
111
|
+
console.error(`[_HANDLE_NEXT_STEP_DECISION_ERROR]`, {
|
|
112
|
+
error: errorMessage,
|
|
113
|
+
decisionError,
|
|
114
|
+
decisionId: decision.id,
|
|
115
|
+
sourceNodeId: nodeId
|
|
116
|
+
});
|
|
117
|
+
state.errors.push({
|
|
118
|
+
nodeId: decision.id,
|
|
119
|
+
message: errorMessage,
|
|
120
|
+
details: {
|
|
121
|
+
sourceNodeId: nodeId,
|
|
122
|
+
originalError: decisionError.message
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
})();
|
|
127
|
+
decisionExecutionPromises.push(decisionPromise);
|
|
128
|
+
}
|
|
129
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_WAITING_FOR_DECISIONS]', { nodeId, count: decisionExecutionPromises.length });
|
|
130
|
+
await Promise.all(decisionExecutionPromises);
|
|
131
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_DECISIONS_COMPLETE]', { nodeId });
|
|
132
|
+
} else {
|
|
133
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_CALLING_HANDLE_NEXT_STEP_FOR_NON_DECISION]', { nodeId, next: node.next });
|
|
134
|
+
await handleNextStep(output, nodeId, node.next, state);
|
|
135
|
+
}
|
|
136
|
+
} else {
|
|
137
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_NO_NEXT_NODE_IMPLICIT_TERMINATION]', { nodeId, output });
|
|
138
|
+
const result = output;
|
|
139
|
+
state.results[nodeId] = result;
|
|
140
|
+
}
|
|
141
|
+
if (isPhaseNode(node)) {
|
|
142
|
+
dispatchEvent(state.eventState, createPhaseNodeEvent(nodeId, 'end', node, {
|
|
143
|
+
input,
|
|
144
|
+
output
|
|
145
|
+
}), state.context);
|
|
146
|
+
} else {
|
|
147
|
+
dispatchEvent(state.eventState, createAggregatorNodeEvent(nodeId, 'end', node, {
|
|
148
|
+
input,
|
|
149
|
+
output
|
|
150
|
+
}), state.context);
|
|
151
|
+
}
|
|
152
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_IIFE_RETURNING_OUTPUT]', { nodeId, output });
|
|
153
|
+
return output;
|
|
154
|
+
} catch (error) {
|
|
155
|
+
// eslint-disable-next-line no-console
|
|
156
|
+
console.error(`[EXECUTE_NODE_RECURSIVE_IIFE_ERROR] Error executing node ${nodeId}:`, {
|
|
157
|
+
error,
|
|
158
|
+
nodeId
|
|
159
|
+
});
|
|
160
|
+
state.errors.push({
|
|
161
|
+
nodeId,
|
|
162
|
+
message: error.message
|
|
163
|
+
});
|
|
164
|
+
// Clean up any pending aggregator deferred on error
|
|
165
|
+
if (state.aggregatorDeferreds.has(nodeId)) {
|
|
166
|
+
const deferred = state.aggregatorDeferreds.get(nodeId);
|
|
167
|
+
if (deferred) {
|
|
168
|
+
deferred.reject(error);
|
|
169
|
+
}
|
|
170
|
+
state.aggregatorDeferreds.delete(nodeId);
|
|
171
|
+
}
|
|
172
|
+
throw error;
|
|
173
|
+
} finally{
|
|
174
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_IIFE_FINALLY]', { nodeId, hasAggregatorDeferred: state.aggregatorDeferreds.has(nodeId) });
|
|
175
|
+
// If a node completed (not pending via deferred mechanism) or an error occurred.
|
|
176
|
+
// An aggregator that is still pending (has a deferred) should keep its promise in activeExecutions.
|
|
177
|
+
if (!state.aggregatorDeferreds.has(nodeId)) {
|
|
178
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_IIFE_FINALLY_DELETING_ACTIVE_EXECUTION]', { nodeId });
|
|
179
|
+
state.activeExecutions.delete(nodeId);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
})();
|
|
183
|
+
// Store the promise from the IIFE.
|
|
184
|
+
// If it's an aggregator that went pending, executionPromise IS deferred.promise.
|
|
185
|
+
// If it's an aggregator that became ready, executionPromise is a promise resolving to its output.
|
|
186
|
+
// If it's a phase node, executionPromise is a promise resolving to its output.
|
|
187
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_SETTING_ACTIVE_EXECUTION]', { nodeId });
|
|
188
|
+
state.activeExecutions.set(nodeId, executionPromise);
|
|
189
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_END_RETURNING_PROMISE]', { nodeId });
|
|
190
|
+
return executionPromise;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export { executeNode };
|
|
194
|
+
//# sourceMappingURL=node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.js","sources":["../../src/execution/node.ts"],"sourcesContent":["import { Context } from '../context';\nimport { createAggregatorNodeEvent, createPhaseNodeEvent } from '../event/node';\nimport { createDecisionEvent } from '../event/transition';\nimport { Input } from '../input';\nimport { AggregatorNode, isAggregatorNode } from '../node/aggregatornode';\nimport { isPhaseNode, PhaseNode } from '../node/phasenode';\nimport { Output } from '../output';\nimport { Connection } from '../transition/connection';\nimport { Decision, isDecision } from '../transition/decision';\nimport { Termination } from '../transition/termination';\nimport {\n executeAggregatorNode\n} from './aggregator';\nimport { dispatchEvent } from './event';\nimport { handleNextStep } from './next';\nimport { executePhase } from './phase';\nimport { ExecutionState } from './process';\n\nexport async function executeNode(\n nodeId: string,\n input: Input,\n state: ExecutionState\n): Promise<Output> {\n\n //console.log('[EXECUTE_NODE_RECURSIVE_START]', { nodeId, input, phaseResultsKeys: Object.keys(state.phaseResults), activeExecutionsKeys: Array.from(state.activeExecutions.keys()), aggregatorDeferredsKeys: Array.from(state.aggregatorDeferreds.keys()) });\n\n // 1. Check if result is already cached in phaseResults (final output, node fully completed)\n if (state.phaseResults[nodeId]) {\n\n //console.log('[EXECUTE_NODE_RECURSIVE_CACHE_HIT_PHASERESULTS]', { nodeId, result: state.phaseResults[nodeId] });\n return state.phaseResults[nodeId];\n }\n\n const node = state.process.phases[nodeId] as PhaseNode | AggregatorNode;\n if (!node) {\n const error = new Error(`Node with ID \"${nodeId}\" not found.`);\n\n //console.error('[EXECUTE_NODE_RECURSIVE_NODE_NOT_FOUND]', { nodeId, error });\n state.errors.push({ nodeId, message: error.message });\n throw error;\n }\n\n //console.log('[EXECUTE_NODE_RECURSIVE_NODE_FOUND]', { nodeId, nodeType: node.constructor.name, node });\n\n // 2. Handle active/pending executions\n // If it's an aggregator that has a deferred promise, it means it's pending.\n // We need to re-evaluate it with the current input. The IIFE below will handle this.\n if (state.activeExecutions.has(nodeId) && !isAggregatorNode(node)) {\n // For non-aggregators, if already active, return the promise.\n // Aggregators will fall through to the IIFE to allow input processing.\n // The IIFE itself handles returning a shared deferred promise if needed.\n\n //console.log('[EXECUTE_NODE_RECURSIVE_ACTIVE_EXECUTION_HIT_NON_AGGREGATOR]', { nodeId });\n return state.activeExecutions.get(nodeId)!;\n }\n // If it IS an aggregator and state.activeExecutions.has(nodeId),\n // it means its deferred.promise might be in activeExecutions from a previous input that made it pending.\n // The IIFE logic below will correctly retrieve this deferred (if it exists and is still relevant)\n // from state.aggregatorDeferreds.get(nodeId) and use its promise, or process the input.\n\n\n //console.log('[EXECUTE_NODE_RECURSIVE_CONTINUING_TO_EXECUTION_LOGIC]', { nodeId, isActive: state.activeExecutions.has(nodeId), isAggregator: isAggregatorNode(node), hasDeferred: state.aggregatorDeferreds.has(nodeId) });\n // If it's an aggregator and it's pending (has a deferred), we fall through to re-execute its logic within the IIFE.\n // If it's the first call to any node, we fall through.\n\n // 3. Mark as active and execute (or re-evaluate pending aggregator)\n const executionPromise = (async (): Promise<Output> => {\n\n //console.log('[EXECUTE_NODE_RECURSIVE_IIFE_START]', { nodeId, input });\n try {\n let output: Output;\n\n if (isAggregatorNode(node)) {\n\n dispatchEvent(\n state.eventState,\n createAggregatorNodeEvent(nodeId, 'start', node, { input }),\n state.context\n );\n\n output = await executeAggregatorNode(nodeId, node, input, state);\n } else if (isPhaseNode(node)) {\n\n dispatchEvent(state.eventState, createPhaseNodeEvent(nodeId, 'start', node, { input }), state.context);\n\n if (node.prepare) {\n const [preparedInput, preparedContext] = await node.prepare(input, state.context);\n input = preparedInput;\n state.context = preparedContext;\n }\n\n dispatchEvent(state.eventState, createPhaseNodeEvent(nodeId, 'prepared', node, { input }), state.context);\n\n\n output = await executePhase(nodeId, node, input, state);\n\n if (node.process) {\n const [processedOutput, processedContext] = await node.process(output, state.context);\n output = processedOutput;\n state.context = processedContext;\n }\n\n dispatchEvent(state.eventState, createPhaseNodeEvent(nodeId, 'processed', node, { input, output }), state.context);\n\n //console.log('[EXECUTE_NODE_RECURSIVE_PHASE_NODE_EXECUTE_END]', { nodeId, output });\n } else {\n const error = new Error(`Unknown or invalid node type for ID \"${nodeId}\". Expected PhaseNode or AggregatorNode.`);\n\n //console.error('[EXECUTE_NODE_RECURSIVE_UNKNOWN_NODE_TYPE]', { nodeId, node, error });\n throw error;\n }\n\n state.phaseResults[nodeId] = output; // Set final output once ready/executed\n\n //console.log('[EXECUTE_NODE_RECURSIVE_PHASE_RESULT_CACHED]', { nodeId, output });\n\n // 4. Handle next step\n if (node.next) {\n\n //console.log('[EXECUTE_NODE_RECURSIVE_HANDLING_NEXT_STEP]', { nodeId, nextType: node.next.constructor.name, next: node.next });\n if (Array.isArray(node.next) && node.next.length > 0 && node.next.every(isDecision)) {\n\n //console.log('[EXECUTE_NODE_RECURSIVE_DECISIONS_FOUND]', { nodeId, count: node.next.length, decisions: node.next });\n const decisions = node.next as Decision<Output, Context>[];\n const decisionExecutionPromises: Promise<void>[] = [];\n for (const decision of decisions) {\n\n dispatchEvent(state.eventState, createDecisionEvent(nodeId, 'start', decision, { output }), state.context);\n\n const decisionPromise = (async () => {\n\n //console.log('[EXECUTE_NODE_RECURSIVE_DECISION_EXECUTE_START]', { nodeId, decisionId: decision.id, output });\n try {\n const decisionOutcome = await decision.decide(output, state.context);\n dispatchEvent(state.eventState, createDecisionEvent(nodeId, 'decide', decision, { output, result: decisionOutcome }), state.context);\n\n //console.log('[EXECUTE_NODE_RECURSIVE_DECISION_OUTCOME]', { nodeId, decisionId: decision.id, decisionOutcome });\n await handleNextStep(output, decision.id, decisionOutcome, state);\n dispatchEvent(state.eventState, createDecisionEvent(nodeId, 'end', decision), state.context);\n } catch (decisionError: any) {\n const errorMessage = `Decision error on '${decision.id}' for node '${nodeId}': ${decisionError.message}`;\n // eslint-disable-next-line no-console\n console.error(`[_HANDLE_NEXT_STEP_DECISION_ERROR]`, {\n error: errorMessage,\n decisionError,\n decisionId: decision.id,\n sourceNodeId: nodeId\n });\n state.errors.push({\n nodeId: decision.id,\n message: errorMessage,\n details: { sourceNodeId: nodeId, originalError: decisionError.message }\n });\n }\n })();\n decisionExecutionPromises.push(decisionPromise);\n }\n\n //console.log('[EXECUTE_NODE_RECURSIVE_WAITING_FOR_DECISIONS]', { nodeId, count: decisionExecutionPromises.length });\n await Promise.all(decisionExecutionPromises);\n\n //console.log('[EXECUTE_NODE_RECURSIVE_DECISIONS_COMPLETE]', { nodeId });\n } else {\n\n //console.log('[EXECUTE_NODE_RECURSIVE_CALLING_HANDLE_NEXT_STEP_FOR_NON_DECISION]', { nodeId, next: node.next });\n await handleNextStep(output, nodeId, node.next as Termination<Output, Context> | Connection<Output, Context>[] | Decision<Output, Context>[], state);\n }\n } else {\n\n //console.log('[EXECUTE_NODE_RECURSIVE_NO_NEXT_NODE_IMPLICIT_TERMINATION]', { nodeId, output });\n const result: Output = output;\n state.results[nodeId] = result;\n }\n\n if (isPhaseNode(node)) {\n dispatchEvent(state.eventState, createPhaseNodeEvent(nodeId, 'end', node, { input, output }), state.context);\n } else {\n dispatchEvent(state.eventState, createAggregatorNodeEvent(nodeId, 'end', node, { input, output }), state.context);\n }\n\n //console.log('[EXECUTE_NODE_RECURSIVE_IIFE_RETURNING_OUTPUT]', { nodeId, output });\n return output;\n } catch (error: any) {\n // eslint-disable-next-line no-console\n console.error(`[EXECUTE_NODE_RECURSIVE_IIFE_ERROR] Error executing node ${nodeId}:`, { error, nodeId });\n state.errors.push({ nodeId, message: error.message });\n // Clean up any pending aggregator deferred on error\n if (state.aggregatorDeferreds.has(nodeId)) {\n const deferred = state.aggregatorDeferreds.get(nodeId);\n if (deferred) {\n deferred.reject(error);\n }\n state.aggregatorDeferreds.delete(nodeId);\n }\n throw error;\n } finally {\n\n //console.log('[EXECUTE_NODE_RECURSIVE_IIFE_FINALLY]', { nodeId, hasAggregatorDeferred: state.aggregatorDeferreds.has(nodeId) });\n // If a node completed (not pending via deferred mechanism) or an error occurred.\n // An aggregator that is still pending (has a deferred) should keep its promise in activeExecutions.\n if (!state.aggregatorDeferreds.has(nodeId)) {\n\n //console.log('[EXECUTE_NODE_RECURSIVE_IIFE_FINALLY_DELETING_ACTIVE_EXECUTION]', { nodeId });\n state.activeExecutions.delete(nodeId);\n }\n }\n })();\n\n // Store the promise from the IIFE.\n // If it's an aggregator that went pending, executionPromise IS deferred.promise.\n // If it's an aggregator that became ready, executionPromise is a promise resolving to its output.\n // If it's a phase node, executionPromise is a promise resolving to its output.\n\n //console.log('[EXECUTE_NODE_RECURSIVE_SETTING_ACTIVE_EXECUTION]', { nodeId });\n state.activeExecutions.set(nodeId, executionPromise);\n\n //console.log('[EXECUTE_NODE_RECURSIVE_END_RETURNING_PROMISE]', { nodeId });\n return executionPromise;\n\n}\n\n"],"names":["executeNode","nodeId","input","state","phaseResults","node","process","phases","error","Error","errors","push","message","activeExecutions","has","isAggregatorNode","get","executionPromise","output","dispatchEvent","eventState","createAggregatorNodeEvent","context","executeAggregatorNode","isPhaseNode","createPhaseNodeEvent","prepare","preparedInput","preparedContext","executePhase","processedOutput","processedContext","next","Array","isArray","length","every","isDecision","decisions","decisionExecutionPromises","decision","createDecisionEvent","decisionPromise","decisionOutcome","decide","result","handleNextStep","id","decisionError","errorMessage","console","decisionId","sourceNodeId","details","originalError","Promise","all","results","aggregatorDeferreds","deferred","reject","delete","set"],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Input } from '../input';
|
|
2
|
+
import { PhaseNode } from '../node/phasenode';
|
|
3
|
+
import { Output } from '../output';
|
|
4
|
+
import { ExecutionState } from './process';
|
|
5
|
+
export declare function executePhase(nodeId: string, node: PhaseNode, input: Input, state: ExecutionState): Promise<Output>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createPhaseEvent } from '../event/phase.js';
|
|
2
|
+
import { dispatchEvent } from './event.js';
|
|
3
|
+
|
|
4
|
+
async function executePhase(nodeId, node, input, state) {
|
|
5
|
+
dispatchEvent(state.eventState, createPhaseEvent(nodeId, 'start', node.phase, {
|
|
6
|
+
input
|
|
7
|
+
}), state.context);
|
|
8
|
+
if (node.phase.verify) {
|
|
9
|
+
const verifyResponse = await node.phase.verify(input);
|
|
10
|
+
if (!verifyResponse.verified) {
|
|
11
|
+
throw new Error(verifyResponse.messages.join('\n'));
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const output = await node.phase.execute(input);
|
|
15
|
+
dispatchEvent(state.eventState, createPhaseEvent(nodeId, 'execute', node.phase, {
|
|
16
|
+
input,
|
|
17
|
+
output
|
|
18
|
+
}), state.context);
|
|
19
|
+
return output;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export { executePhase };
|
|
23
|
+
//# sourceMappingURL=phase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"phase.js","sources":["../../src/execution/phase.ts"],"sourcesContent":["import { createPhaseEvent } from '../event/phase';\nimport { Input } from '../input';\nimport { PhaseNode } from '../node/phasenode';\nimport { Output } from '../output';\nimport { dispatchEvent } from './event';\nimport { ExecutionState } from './process';\n\nexport async function executePhase(nodeId: string, node: PhaseNode, input: Input, state: ExecutionState): Promise<Output> {\n dispatchEvent(state.eventState, createPhaseEvent(nodeId, 'start', node.phase, { input }), state.context);\n\n if (node.phase.verify) {\n const verifyResponse = await node.phase.verify(input);\n if (!verifyResponse.verified) {\n throw new Error(verifyResponse.messages.join('\\n'));\n }\n }\n\n const output: Output = await node.phase.execute(input);\n\n dispatchEvent(state.eventState, createPhaseEvent(nodeId, 'execute', node.phase, { input, output }), state.context);\n return output;\n}"],"names":["executePhase","nodeId","node","input","state","dispatchEvent","eventState","createPhaseEvent","phase","context","verify","verifyResponse","verified","Error","messages","join","output","execute"],"mappings":";;;AAOO,eAAeA,aAAaC,MAAc,EAAEC,IAAe,EAAEC,KAAY,EAAEC,KAAqB,EAAA;IACnGC,aAAAA,CAAcD,KAAAA,CAAME,UAAU,EAAEC,gBAAAA,CAAiBN,QAAQ,OAAA,EAASC,IAAAA,CAAKM,KAAK,EAAE;AAAEL,QAAAA;AAAM,KAAA,CAAA,EAAIC,MAAMK,OAAO,CAAA;AAEvG,IAAA,IAAIP,IAAAA,CAAKM,KAAK,CAACE,MAAM,EAAE;AACnB,QAAA,MAAMC,iBAAiB,MAAMT,IAAAA,CAAKM,KAAK,CAACE,MAAM,CAACP,KAAAA,CAAAA;QAC/C,IAAI,CAACQ,cAAAA,CAAeC,QAAQ,EAAE;AAC1B,YAAA,MAAM,IAAIC,KAAAA,CAAMF,cAAAA,CAAeG,QAAQ,CAACC,IAAI,CAAC,IAAA,CAAA,CAAA;AACjD,QAAA;AACJ,IAAA;AAEA,IAAA,MAAMC,SAAiB,MAAMd,IAAAA,CAAKM,KAAK,CAACS,OAAO,CAACd,KAAAA,CAAAA;IAEhDE,aAAAA,CAAcD,KAAAA,CAAME,UAAU,EAAEC,gBAAAA,CAAiBN,QAAQ,SAAA,EAAWC,IAAAA,CAAKM,KAAK,EAAE;AAAEL,QAAAA,KAAAA;AAAOa,QAAAA;AAAO,KAAA,CAAA,EAAIZ,MAAMK,OAAO,CAAA;IACjH,OAAOO,MAAAA;AACX;;;;"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Context } from '../context';
|
|
2
|
+
import { AggregatorState } from './aggregator';
|
|
3
|
+
import { Input } from '../input';
|
|
4
|
+
import { Output } from '../output';
|
|
5
|
+
import { Process } from '../process';
|
|
6
|
+
import { Beginning } from '../transition/beginning';
|
|
7
|
+
import { Event, EventHandler, EventState } from '../event';
|
|
8
|
+
export interface PhaseResults {
|
|
9
|
+
[key: string]: Output;
|
|
10
|
+
}
|
|
11
|
+
export interface ProcessResults {
|
|
12
|
+
[key: string]: Output;
|
|
13
|
+
}
|
|
14
|
+
interface ProcessExecutionError {
|
|
15
|
+
message: string;
|
|
16
|
+
details?: any;
|
|
17
|
+
nodeId?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface ProcessExecutionOptions<I extends Input = Input, C extends Context = Context> {
|
|
20
|
+
input: I;
|
|
21
|
+
context: C;
|
|
22
|
+
eventHandlers?: ReadonlyArray<EventHandler<Event, C>>;
|
|
23
|
+
}
|
|
24
|
+
export declare const DEFAULT_PROCESS_EXECUTION_OPTIONS: ProcessExecutionOptions<Input, Context>;
|
|
25
|
+
export interface ExecutionState<C extends Context = Context> extends AggregatorState {
|
|
26
|
+
process: Readonly<Process>;
|
|
27
|
+
context: C;
|
|
28
|
+
phaseResults: Record<string, Output>;
|
|
29
|
+
results: Record<string, Output>;
|
|
30
|
+
activeExecutions: Map<string, Promise<Output>>;
|
|
31
|
+
errors: ProcessExecutionError[];
|
|
32
|
+
readonly eventState: Readonly<EventState<C>>;
|
|
33
|
+
}
|
|
34
|
+
export declare function executeProcess<I extends Input = Input, O extends Output = Output, C extends Context = Context>(processInstance: Readonly<Process>, beginning: Beginning<I, C>, options?: Partial<ProcessExecutionOptions<I, C>>): Promise<[Record<string, O>, Record<string, O>, C]>;
|
|
35
|
+
export {};
|