@cnstra/core 2.4.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/CNS.d.ts +22 -0
- package/dist/CNS.d.ts.map +1 -1
- package/dist/CNSStimulation.d.ts +33 -1
- package/dist/CNSStimulation.d.ts.map +1 -1
- package/dist/index.cjs +212 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +212 -42
- package/dist/index.js.map +1 -1
- package/dist/interfaces/ICNS.d.ts +7 -0
- package/dist/interfaces/ICNS.d.ts.map +1 -1
- package/dist/types/TCNSStimulationDrain.d.ts +37 -0
- package/dist/types/TCNSStimulationDrain.d.ts.map +1 -0
- package/dist/types/TCNSStimulationOptions.d.ts +18 -0
- package/dist/types/TCNSStimulationOptions.d.ts.map +1 -1
- package/dist/types/TCNSStimulationResponse.d.ts +40 -0
- package/dist/types/TCNSStimulationResponse.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/CNS.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { CNSStimulation } from './CNSStimulation';
|
|
|
6
6
|
import { TCNSSignal } from './types/TCNSSignal';
|
|
7
7
|
import { CNSInstanceNeuronQueue } from './CNSInstanceNeuronQueue';
|
|
8
8
|
import { TCNSStimulationResponse } from './types/TCNSStimulationResponse';
|
|
9
|
+
import { TCNSStimulationDrain } from './types/TCNSStimulationDrain';
|
|
9
10
|
import { TCNSNeuronActivationTask } from './types/TCNSNeuronActivationTask';
|
|
10
11
|
import { CNSNetwork } from './CNSNetwork';
|
|
11
12
|
import { ICNS } from './interfaces/ICNS';
|
|
@@ -26,6 +27,10 @@ export declare class CNS<TNeuron extends TCNSNeuron<any, any>, TDendrite extends
|
|
|
26
27
|
* Global response listeners applied to every stimulation.
|
|
27
28
|
*/
|
|
28
29
|
private readonly globalResponseListeners;
|
|
30
|
+
/**
|
|
31
|
+
* Global batch-boundary listeners applied to every stimulation.
|
|
32
|
+
*/
|
|
33
|
+
private readonly globalDrainListeners;
|
|
29
34
|
/**
|
|
30
35
|
* Shared, app/organism-wide value handed to every dendrite as `ctx.global`.
|
|
31
36
|
* Stored untyped (the type is baked into neurons via `neuronFactory().withGlobal<T>()`);
|
|
@@ -34,6 +39,23 @@ export declare class CNS<TNeuron extends TCNSNeuron<any, any>, TDendrite extends
|
|
|
34
39
|
readonly global?: unknown;
|
|
35
40
|
constructor(neurons: TNeuron[], options?: TCNSOptions | undefined, global?: unknown);
|
|
36
41
|
addResponseListener(listener: (response: TCNSStimulationResponse) => void | Promise<void>): () => void;
|
|
42
|
+
/**
|
|
43
|
+
* Register a listener called once at the end of every synchronous turn of
|
|
44
|
+
* every stimulation - see {@link TCNSStimulationDrain}. This is how an
|
|
45
|
+
* integration (a state manager, an in-memory database) installs a single
|
|
46
|
+
* commit point for the whole organism instead of passing `onDrain` per call.
|
|
47
|
+
*
|
|
48
|
+
* Returns an unsubscribe function.
|
|
49
|
+
*/
|
|
50
|
+
addDrainListener(listener: (drain: TCNSStimulationDrain) => void): () => void;
|
|
51
|
+
/**
|
|
52
|
+
* Fan a drain out to the local and global listeners, or return undefined when
|
|
53
|
+
* there are none so the stimulation can skip the boundary check entirely.
|
|
54
|
+
*
|
|
55
|
+
* Listener errors are isolated: a drain is a notification, and one broken
|
|
56
|
+
* flush must not stop the others or derail the stimulation that triggered it.
|
|
57
|
+
*/
|
|
58
|
+
private wrapOnDrain;
|
|
37
59
|
private wrapOnResponse;
|
|
38
60
|
stimulate(signalOrSignals: TCNSSignal<CNSCollateral<unknown>> | TCNSSignal<CNSCollateral<unknown>>[], options?: TCNSStimulationOptions<TCNSStimulationResponse>): CNSStimulation<TNeuron, TDendrite>;
|
|
39
61
|
/**
|
package/dist/CNS.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CNS.d.ts","sourceRoot":"","sources":["../src/CNS.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAC1E,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,qBAAa,GAAG,CACZ,OAAO,SAAS,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,EACpC,SAAS,SAAS,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAC7E,YAAW,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"CNS.d.ts","sourceRoot":"","sources":["../src/CNS.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAC1E,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,qBAAa,GAAG,CACZ,OAAO,SAAS,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,EACpC,SAAS,SAAS,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAC7E,YAAW,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC;IAoC7B,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE;aACrB,OAAO,CAAC,EAAE,WAAW;IAnCzC;;OAEG;IACH,SAAgB,OAAO,EAAE,UAAU,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAExD;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,mBAAmB,kCACI;IAE1C;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAEjC;IAEP;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAE9B;IAEP;;;;OAIG;IACH,SAAgB,MAAM,CAAC,EAAE,OAAO,CAAC;gBAGV,OAAO,EAAE,OAAO,EAAE,EACrB,OAAO,CAAC,EAAE,WAAW,YAAA,EACrC,MAAM,CAAC,EAAE,OAAO;IAMb,mBAAmB,CACtB,QAAQ,EAAE,CAAC,QAAQ,EAAE,uBAAuB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GACtE,MAAM,IAAI;IAWb;;;;;;;OAOG;IACI,gBAAgB,CACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,GAChD,MAAM,IAAI;IAWb;;;;;;OAMG;IACH,OAAO,CAAC,WAAW;IAsBnB,OAAO,CAAC,cAAc;IAmDf,SAAS,CACZ,eAAe,EACT,UAAU,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,GAClC,UAAU,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,EAAE,EAC1C,OAAO,CAAC,EAAE,sBAAsB,CAAC,uBAAuB,CAAC,GAC1D,cAAc,CAAC,OAAO,EAAE,SAAS,CAAC;IAarC;;OAEG;IACI,QAAQ,CACX,KAAK,EAAE,wBAAwB,CAAC,OAAO,CAAC,EAAE,EAC1C,OAAO,CAAC,EAAE,sBAAsB,CAAC,uBAAuB,CAAC,GAC1D,cAAc,CAAC,OAAO,EAAE,SAAS,CAAC;CAYxC"}
|
package/dist/CNSStimulation.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { TCNSNeuronActivationTask } from './types/TCNSNeuronActivationTask';
|
|
|
9
9
|
import { CNS } from './CNS';
|
|
10
10
|
import { TCNSNeuronActivationTaskFailure } from './types/TCNSNeuronActivationTaskFailure';
|
|
11
11
|
import { TCNSStimulationResponse } from './types/TCNSStimulationResponse';
|
|
12
|
+
import { TCNSStimulationDrain } from './types/TCNSStimulationDrain';
|
|
12
13
|
import { CNSCollateral } from './CNSCollateral';
|
|
13
14
|
export declare class CNSStimulation<TNeuron extends TCNSNeuron<any, any>, TDendrite extends TCNSDendrite<any, any, any> = TCNSDendrite<any, any, any>> {
|
|
14
15
|
readonly cns: CNS<TNeuron, TDendrite>;
|
|
@@ -23,9 +24,11 @@ export declare class CNSStimulation<TNeuron extends TCNSNeuron<any, any>, TDendr
|
|
|
23
24
|
private activeTasks?;
|
|
24
25
|
private pumping;
|
|
25
26
|
private needsPump;
|
|
27
|
+
private turnDepth;
|
|
26
28
|
private readonly neuronVisitMap?;
|
|
27
29
|
private readonly instanceNeuronQueue;
|
|
28
30
|
private scheduledCount;
|
|
31
|
+
private reservedActivations;
|
|
29
32
|
private pendingTasks?;
|
|
30
33
|
private failedTasks?;
|
|
31
34
|
private completed?;
|
|
@@ -40,12 +43,18 @@ export declare class CNSStimulation<TNeuron extends TCNSNeuron<any, any>, TDendr
|
|
|
40
43
|
* undefined when there is neither a local nor any global listener.
|
|
41
44
|
*/
|
|
42
45
|
private readonly onResponse?;
|
|
46
|
+
/**
|
|
47
|
+
* The (already wrapped) drain listener, or undefined when there is neither a
|
|
48
|
+
* local nor any global one. When undefined, endTurn() bails immediately, so a
|
|
49
|
+
* stimulation with no drain listener pays only the turn depth counter.
|
|
50
|
+
*/
|
|
51
|
+
private readonly onDrain?;
|
|
43
52
|
/**
|
|
44
53
|
* Track active SCCs: SCC index -> count of active neurons in that SCC.
|
|
45
54
|
* Only allocated when context auto-cleanup is enabled.
|
|
46
55
|
*/
|
|
47
56
|
private readonly activeSccCounts?;
|
|
48
|
-
constructor(cns: CNS<TNeuron, TDendrite>, instanceNeuronQueue: CNSInstanceNeuronQueue<TNeuron>, options?: TCNSStimulationOptions<TCNSStimulationResponse> | undefined, onResponse?: (response: TCNSStimulationResponse) => void | Promise<void
|
|
57
|
+
constructor(cns: CNS<TNeuron, TDendrite>, instanceNeuronQueue: CNSInstanceNeuronQueue<TNeuron>, options?: TCNSStimulationOptions<TCNSStimulationResponse> | undefined, onResponse?: (response: TCNSStimulationResponse) => void | Promise<void>, onDrain?: (drain: TCNSStimulationDrain) => void);
|
|
49
58
|
private pushFailedTask;
|
|
50
59
|
private finalizeResolve;
|
|
51
60
|
private finalizeReject;
|
|
@@ -59,6 +68,29 @@ export declare class CNSStimulation<TNeuron extends TCNSNeuron<any, any>, TDendr
|
|
|
59
68
|
private qEnqueue;
|
|
60
69
|
private qGetQueuedTasks;
|
|
61
70
|
private pump;
|
|
71
|
+
/**
|
|
72
|
+
* Open a synchronous turn. Turns nest: a drain is announced only when the
|
|
73
|
+
* outermost one closes, so an enqueue that happens while the pump is already
|
|
74
|
+
* running does not produce its own boundary.
|
|
75
|
+
*/
|
|
76
|
+
private beginTurn;
|
|
77
|
+
/**
|
|
78
|
+
* Close a synchronous turn and, if it was the outermost and nothing more can
|
|
79
|
+
* run without yielding to the event loop, announce the drain.
|
|
80
|
+
*
|
|
81
|
+
* This is the only place the synchronous frontier is observable. A response
|
|
82
|
+
* cannot serve the purpose: responses are emitted when an activation
|
|
83
|
+
* *finishes*, but a turn just as often ends when one *starts* and returns a
|
|
84
|
+
* promise - at which point there is nothing left to emit a response from.
|
|
85
|
+
*/
|
|
86
|
+
private endTurn;
|
|
87
|
+
/**
|
|
88
|
+
* Activations that exist (or are reserved) but whose dendrite body has not
|
|
89
|
+
* been invoked yet: sitting in the ring buffer, created and held in
|
|
90
|
+
* pendingTasks, or reserved by an array fan-out mid-dispatch. Subscribers
|
|
91
|
+
* parked behind an async onResponse land here too - their body has not run.
|
|
92
|
+
*/
|
|
93
|
+
private get pendingActivations();
|
|
62
94
|
private tryResolveCompleted;
|
|
63
95
|
waitUntilComplete(): Promise<void>;
|
|
64
96
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CNSStimulation.d.ts","sourceRoot":"","sources":["../src/CNSStimulation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,2BAA2B,EAAE,MAAM,0CAA0C,CAAC;AACvF,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAE5B,OAAO,EAAE,+BAA+B,EAAE,MAAM,yCAAyC,CAAC;AAC1F,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAC1E,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"CNSStimulation.d.ts","sourceRoot":"","sources":["../src/CNSStimulation.ts"],"names":[],"mappings":"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"}
|
package/dist/index.cjs
CHANGED
|
@@ -50,12 +50,14 @@ var CNSDendriteContext = class {
|
|
|
50
50
|
}
|
|
51
51
|
};
|
|
52
52
|
var CNSStimulationResponseImpl = class {
|
|
53
|
-
constructor(stimulation, store, inputSignal, outputSignal, queueLength, hops, error) {
|
|
53
|
+
constructor(stimulation, store, inputSignal, outputSignal, queueLength, pendingActivations, activeActivations, hops, error) {
|
|
54
54
|
this.stimulation = stimulation;
|
|
55
55
|
this.store = store;
|
|
56
56
|
this.inputSignal = inputSignal;
|
|
57
57
|
this.outputSignal = outputSignal;
|
|
58
58
|
this.queueLength = queueLength;
|
|
59
|
+
this.pendingActivations = pendingActivations;
|
|
60
|
+
this.activeActivations = activeActivations;
|
|
59
61
|
this.hops = hops;
|
|
60
62
|
this.error = error;
|
|
61
63
|
}
|
|
@@ -64,7 +66,7 @@ var CNSStimulationResponseImpl = class {
|
|
|
64
66
|
}
|
|
65
67
|
};
|
|
66
68
|
var CNSStimulation = class {
|
|
67
|
-
constructor(cns, instanceNeuronQueue, options, onResponse) {
|
|
69
|
+
constructor(cns, instanceNeuronQueue, options, onResponse, onDrain) {
|
|
68
70
|
this.cns = cns;
|
|
69
71
|
this.options = options;
|
|
70
72
|
this.qHead = 0;
|
|
@@ -75,9 +77,20 @@ var CNSStimulation = class {
|
|
|
75
77
|
// Re-entrancy guard for the pump loop.
|
|
76
78
|
this.pumping = false;
|
|
77
79
|
this.needsPump = false;
|
|
80
|
+
// Nesting depth of the current synchronous turn. Only the outermost close
|
|
81
|
+
// announces a drain - see beginTurn/endTurn.
|
|
82
|
+
this.turnDepth = 0;
|
|
78
83
|
this.scheduledCount = 0;
|
|
84
|
+
// Activations belonging to signals of an in-progress array fan-out that have
|
|
85
|
+
// not been handed to processResponse yet, so the task objects do not exist.
|
|
86
|
+
// processResponse enqueues synchronously, so the first signal's whole subtree
|
|
87
|
+
// drains before the second signal is even looked at; without this counter
|
|
88
|
+
// that subtree's leaf sees an empty queue and reads as "all work done".
|
|
89
|
+
// Counted in activations, not signals, so every public counter shares a unit.
|
|
90
|
+
this.reservedActivations = 0;
|
|
79
91
|
this.isCompleted = false;
|
|
80
92
|
this.completionRejected = false;
|
|
93
|
+
this.onDrain = onDrain;
|
|
81
94
|
this.ctxStore = options?.ctx;
|
|
82
95
|
this.instanceNeuronQueue = instanceNeuronQueue;
|
|
83
96
|
this.onResponse = onResponse;
|
|
@@ -174,18 +187,28 @@ var CNSStimulation = class {
|
|
|
174
187
|
(cb) => {
|
|
175
188
|
this.activeOperations--;
|
|
176
189
|
this.activeTasks.delete(task);
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
if (
|
|
180
|
-
|
|
190
|
+
this.beginTurn();
|
|
191
|
+
try {
|
|
192
|
+
if (typeof cb === "function") cb();
|
|
193
|
+
if (this.qSize > 0 && this.canStartOperation) {
|
|
194
|
+
if (this.pumping) this.needsPump = true;
|
|
195
|
+
else this.pump();
|
|
196
|
+
}
|
|
197
|
+
} finally {
|
|
198
|
+
this.endTurn();
|
|
181
199
|
}
|
|
182
200
|
},
|
|
183
201
|
(err) => {
|
|
184
202
|
this.activeOperations--;
|
|
185
203
|
this.activeTasks.delete(task);
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
204
|
+
this.beginTurn();
|
|
205
|
+
try {
|
|
206
|
+
if (this.qSize > 0 && this.canStartOperation) {
|
|
207
|
+
if (this.pumping) this.needsPump = true;
|
|
208
|
+
else this.pump();
|
|
209
|
+
}
|
|
210
|
+
} finally {
|
|
211
|
+
this.endTurn();
|
|
189
212
|
}
|
|
190
213
|
throw err;
|
|
191
214
|
}
|
|
@@ -201,10 +224,54 @@ var CNSStimulation = class {
|
|
|
201
224
|
this.pump();
|
|
202
225
|
}
|
|
203
226
|
}
|
|
227
|
+
/**
|
|
228
|
+
* Open a synchronous turn. Turns nest: a drain is announced only when the
|
|
229
|
+
* outermost one closes, so an enqueue that happens while the pump is already
|
|
230
|
+
* running does not produce its own boundary.
|
|
231
|
+
*/
|
|
232
|
+
beginTurn() {
|
|
233
|
+
this.turnDepth++;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Close a synchronous turn and, if it was the outermost and nothing more can
|
|
237
|
+
* run without yielding to the event loop, announce the drain.
|
|
238
|
+
*
|
|
239
|
+
* This is the only place the synchronous frontier is observable. A response
|
|
240
|
+
* cannot serve the purpose: responses are emitted when an activation
|
|
241
|
+
* *finishes*, but a turn just as often ends when one *starts* and returns a
|
|
242
|
+
* promise - at which point there is nothing left to emit a response from.
|
|
243
|
+
*/
|
|
244
|
+
endTurn() {
|
|
245
|
+
if (--this.turnDepth > 0) return;
|
|
246
|
+
const onDrain = this.onDrain;
|
|
247
|
+
if (!onDrain) return;
|
|
248
|
+
if (this.pumping) return;
|
|
249
|
+
if (this.qSize > 0 && this.canStartOperation) return;
|
|
250
|
+
this.turnDepth++;
|
|
251
|
+
try {
|
|
252
|
+
onDrain({
|
|
253
|
+
stimulation: this,
|
|
254
|
+
queueLength: this.pendingActivations + this.activeOperations,
|
|
255
|
+
pendingActivations: this.pendingActivations,
|
|
256
|
+
activeActivations: this.activeOperations
|
|
257
|
+
});
|
|
258
|
+
} finally {
|
|
259
|
+
this.turnDepth--;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Activations that exist (or are reserved) but whose dendrite body has not
|
|
264
|
+
* been invoked yet: sitting in the ring buffer, created and held in
|
|
265
|
+
* pendingTasks, or reserved by an array fan-out mid-dispatch. Subscribers
|
|
266
|
+
* parked behind an async onResponse land here too - their body has not run.
|
|
267
|
+
*/
|
|
268
|
+
get pendingActivations() {
|
|
269
|
+
return this.qSize + this.scheduledCount + this.reservedActivations;
|
|
270
|
+
}
|
|
204
271
|
tryResolveCompleted() {
|
|
205
272
|
if (this.isCompleted) return;
|
|
206
273
|
const noActive = this.activeOperations === 0;
|
|
207
|
-
const noPending = this.
|
|
274
|
+
const noPending = this.pendingActivations === 0;
|
|
208
275
|
const aborted = !!this.options?.abortSignal?.aborted;
|
|
209
276
|
if (noPending && noActive || aborted && noActive && !noPending) {
|
|
210
277
|
if (aborted) {
|
|
@@ -276,10 +343,15 @@ var CNSStimulation = class {
|
|
|
276
343
|
* Enqueue activation tasks directly into the stimulation queue
|
|
277
344
|
*/
|
|
278
345
|
enqueueTasks(tasks) {
|
|
279
|
-
|
|
280
|
-
|
|
346
|
+
this.beginTurn();
|
|
347
|
+
try {
|
|
348
|
+
for (const task of tasks) {
|
|
349
|
+
this.qEnqueue(task);
|
|
350
|
+
}
|
|
351
|
+
this.tryResolveCompleted();
|
|
352
|
+
} finally {
|
|
353
|
+
this.endTurn();
|
|
281
354
|
}
|
|
282
|
-
this.tryResolveCompleted();
|
|
283
355
|
}
|
|
284
356
|
get concurrencyEnabled() {
|
|
285
357
|
return this.options?.concurrency !== void 0 && this.options?.concurrency > 0;
|
|
@@ -380,14 +452,19 @@ var CNSStimulation = class {
|
|
|
380
452
|
}
|
|
381
453
|
}
|
|
382
454
|
if (!subscriber) {
|
|
455
|
+
const error = new Error(`Subscriber not found for activation task`);
|
|
383
456
|
this.pushFailedTask({
|
|
384
457
|
task: neuronActivationTask,
|
|
385
|
-
error
|
|
386
|
-
`Subscriber not found for activation task`
|
|
387
|
-
),
|
|
458
|
+
error,
|
|
388
459
|
aborted: false
|
|
389
460
|
});
|
|
390
461
|
return () => {
|
|
462
|
+
this.processResponseOrResponses(
|
|
463
|
+
void 0,
|
|
464
|
+
neuronActivationTask.input,
|
|
465
|
+
void 0,
|
|
466
|
+
error
|
|
467
|
+
);
|
|
391
468
|
};
|
|
392
469
|
}
|
|
393
470
|
const neuron2 = subscriber.neuron;
|
|
@@ -434,13 +511,13 @@ var CNSStimulation = class {
|
|
|
434
511
|
error: error instanceof Error ? error : new Error(String(error)),
|
|
435
512
|
aborted: isAborted
|
|
436
513
|
});
|
|
437
|
-
this.processResponseOrResponses(
|
|
438
|
-
neuron2,
|
|
439
|
-
inputSignal,
|
|
440
|
-
void 0,
|
|
441
|
-
error
|
|
442
|
-
);
|
|
443
514
|
return () => {
|
|
515
|
+
this.processResponseOrResponses(
|
|
516
|
+
neuron2,
|
|
517
|
+
inputSignal,
|
|
518
|
+
void 0,
|
|
519
|
+
error
|
|
520
|
+
);
|
|
444
521
|
};
|
|
445
522
|
}
|
|
446
523
|
const maxDuration = neuron2.maxDuration;
|
|
@@ -510,8 +587,26 @@ var CNSStimulation = class {
|
|
|
510
587
|
this.processResponse(emitter, inputSignal, void 0, error);
|
|
511
588
|
return;
|
|
512
589
|
}
|
|
513
|
-
|
|
514
|
-
|
|
590
|
+
let perSignal;
|
|
591
|
+
if (!error) {
|
|
592
|
+
perSignal = new Array(outputSignalOrSignals.length);
|
|
593
|
+
let reserved = 0;
|
|
594
|
+
for (let i = 0; i < outputSignalOrSignals.length; i++) {
|
|
595
|
+
const c = outputSignalOrSignals[i]?.collateral;
|
|
596
|
+
const n = c ? this.cns.network.getSubscribers(c).length : 0;
|
|
597
|
+
perSignal[i] = n;
|
|
598
|
+
reserved += n;
|
|
599
|
+
}
|
|
600
|
+
this.reservedActivations += reserved;
|
|
601
|
+
}
|
|
602
|
+
for (let i = 0; i < outputSignalOrSignals.length; i++) {
|
|
603
|
+
if (perSignal) this.reservedActivations -= perSignal[i];
|
|
604
|
+
this.processResponse(
|
|
605
|
+
emitter,
|
|
606
|
+
inputSignal,
|
|
607
|
+
outputSignalOrSignals[i],
|
|
608
|
+
error
|
|
609
|
+
);
|
|
515
610
|
}
|
|
516
611
|
return;
|
|
517
612
|
}
|
|
@@ -565,7 +660,9 @@ var CNSStimulation = class {
|
|
|
565
660
|
this.ctxStore,
|
|
566
661
|
inputSignal,
|
|
567
662
|
outputSignal,
|
|
568
|
-
this.
|
|
663
|
+
this.pendingActivations + this.activeOperations,
|
|
664
|
+
this.pendingActivations,
|
|
665
|
+
this.activeOperations,
|
|
569
666
|
this.options?.maxNeuronHops && emitter ? this.neuronVisitMap?.get(emitter) ?? 0 : void 0,
|
|
570
667
|
error
|
|
571
668
|
)
|
|
@@ -583,21 +680,35 @@ var CNSStimulation = class {
|
|
|
583
680
|
if (maybePromise && typeof maybePromise.then === "function") {
|
|
584
681
|
maybePromise.then(
|
|
585
682
|
() => {
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
683
|
+
this.beginTurn();
|
|
684
|
+
try {
|
|
685
|
+
for (let i = 0; i < subscriberActivationTasks.length; i++) {
|
|
686
|
+
this.scheduledCount--;
|
|
687
|
+
this.pendingTasks?.delete(
|
|
688
|
+
subscriberActivationTasks[i]
|
|
689
|
+
);
|
|
690
|
+
this.qEnqueue(subscriberActivationTasks[i]);
|
|
691
|
+
}
|
|
692
|
+
this.tryResolveCompleted();
|
|
693
|
+
} finally {
|
|
694
|
+
this.endTurn();
|
|
590
695
|
}
|
|
591
|
-
this.tryResolveCompleted();
|
|
592
696
|
},
|
|
593
697
|
(error2) => {
|
|
594
698
|
this.onResponseError = error2 instanceof Error ? error2 : new Error(String(error2));
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
699
|
+
this.beginTurn();
|
|
700
|
+
try {
|
|
701
|
+
for (let i = 0; i < subscriberActivationTasks.length; i++) {
|
|
702
|
+
this.scheduledCount--;
|
|
703
|
+
this.pendingTasks?.delete(
|
|
704
|
+
subscriberActivationTasks[i]
|
|
705
|
+
);
|
|
706
|
+
this.qEnqueue(subscriberActivationTasks[i]);
|
|
707
|
+
}
|
|
708
|
+
this.tryResolveCompleted();
|
|
709
|
+
} finally {
|
|
710
|
+
this.endTurn();
|
|
599
711
|
}
|
|
600
|
-
this.tryResolveCompleted();
|
|
601
712
|
}
|
|
602
713
|
);
|
|
603
714
|
return;
|
|
@@ -610,12 +721,21 @@ var CNSStimulation = class {
|
|
|
610
721
|
this.tryResolveCompleted();
|
|
611
722
|
}
|
|
612
723
|
responseToSignal(signalOrSignals) {
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
724
|
+
this.beginTurn();
|
|
725
|
+
try {
|
|
726
|
+
if (Array.isArray(signalOrSignals)) {
|
|
727
|
+
this.processResponseOrResponses(
|
|
728
|
+
void 0,
|
|
729
|
+
void 0,
|
|
730
|
+
signalOrSignals
|
|
731
|
+
);
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
this.processResponse(void 0, void 0, signalOrSignals);
|
|
735
|
+
this.tryResolveCompleted();
|
|
736
|
+
} finally {
|
|
737
|
+
this.endTurn();
|
|
616
738
|
}
|
|
617
|
-
this.processResponse(void 0, void 0, signalOrSignals);
|
|
618
|
-
this.tryResolveCompleted();
|
|
619
739
|
}
|
|
620
740
|
};
|
|
621
741
|
|
|
@@ -962,6 +1082,10 @@ var CNS = class {
|
|
|
962
1082
|
* Global response listeners applied to every stimulation.
|
|
963
1083
|
*/
|
|
964
1084
|
this.globalResponseListeners = [];
|
|
1085
|
+
/**
|
|
1086
|
+
* Global batch-boundary listeners applied to every stimulation.
|
|
1087
|
+
*/
|
|
1088
|
+
this.globalDrainListeners = [];
|
|
965
1089
|
this.network = new CNSNetwork(this.neurons);
|
|
966
1090
|
this.global = global;
|
|
967
1091
|
}
|
|
@@ -975,6 +1099,50 @@ var CNS = class {
|
|
|
975
1099
|
if (idx >= 0) this.globalResponseListeners.splice(idx, 1);
|
|
976
1100
|
};
|
|
977
1101
|
}
|
|
1102
|
+
/**
|
|
1103
|
+
* Register a listener called once at the end of every synchronous turn of
|
|
1104
|
+
* every stimulation - see {@link TCNSStimulationDrain}. This is how an
|
|
1105
|
+
* integration (a state manager, an in-memory database) installs a single
|
|
1106
|
+
* commit point for the whole organism instead of passing `onDrain` per call.
|
|
1107
|
+
*
|
|
1108
|
+
* Returns an unsubscribe function.
|
|
1109
|
+
*/
|
|
1110
|
+
addDrainListener(listener) {
|
|
1111
|
+
this.globalDrainListeners.push(listener);
|
|
1112
|
+
let active = true;
|
|
1113
|
+
return () => {
|
|
1114
|
+
if (!active) return;
|
|
1115
|
+
active = false;
|
|
1116
|
+
const idx = this.globalDrainListeners.indexOf(listener);
|
|
1117
|
+
if (idx >= 0) this.globalDrainListeners.splice(idx, 1);
|
|
1118
|
+
};
|
|
1119
|
+
}
|
|
1120
|
+
/**
|
|
1121
|
+
* Fan a drain out to the local and global listeners, or return undefined when
|
|
1122
|
+
* there are none so the stimulation can skip the boundary check entirely.
|
|
1123
|
+
*
|
|
1124
|
+
* Listener errors are isolated: a drain is a notification, and one broken
|
|
1125
|
+
* flush must not stop the others or derail the stimulation that triggered it.
|
|
1126
|
+
*/
|
|
1127
|
+
wrapOnDrain(local) {
|
|
1128
|
+
if (this.globalDrainListeners.length === 0 && !local) return void 0;
|
|
1129
|
+
return (d) => {
|
|
1130
|
+
if (local) {
|
|
1131
|
+
try {
|
|
1132
|
+
local(d);
|
|
1133
|
+
} catch (error) {
|
|
1134
|
+
console.error("[CNS] onDrain listener threw", error);
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
for (let i = 0; i < this.globalDrainListeners.length; i++) {
|
|
1138
|
+
try {
|
|
1139
|
+
this.globalDrainListeners[i](d);
|
|
1140
|
+
} catch (error) {
|
|
1141
|
+
console.error("[CNS] drain listener threw", error);
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
};
|
|
1145
|
+
}
|
|
978
1146
|
wrapOnResponse(local) {
|
|
979
1147
|
if (this.globalResponseListeners.length === 0 && !local) {
|
|
980
1148
|
return void 0;
|
|
@@ -1022,7 +1190,8 @@ var CNS = class {
|
|
|
1022
1190
|
this,
|
|
1023
1191
|
this.instanceNeuronQueue,
|
|
1024
1192
|
options,
|
|
1025
|
-
wrapped
|
|
1193
|
+
wrapped,
|
|
1194
|
+
this.wrapOnDrain(options?.onDrain)
|
|
1026
1195
|
);
|
|
1027
1196
|
stimulation.responseToSignal(signalOrSignals);
|
|
1028
1197
|
return stimulation;
|
|
@@ -1036,7 +1205,8 @@ var CNS = class {
|
|
|
1036
1205
|
this,
|
|
1037
1206
|
this.instanceNeuronQueue,
|
|
1038
1207
|
options,
|
|
1039
|
-
wrapped
|
|
1208
|
+
wrapped,
|
|
1209
|
+
this.wrapOnDrain(options?.onDrain)
|
|
1040
1210
|
);
|
|
1041
1211
|
stimulation.enqueueTasks(tasks);
|
|
1042
1212
|
return stimulation;
|