@cnstra/core 2.2.0 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -2,80 +2,154 @@
2
2
 
3
3
  // src/CNSStimulationContextStore.ts
4
4
  var CNSStimulationContextStore = class {
5
- constructor(ctx = /* @__PURE__ */ new Map()) {
5
+ constructor(ctx) {
6
6
  this.ctx = ctx;
7
7
  }
8
8
  get(key) {
9
- return this.ctx.get(key);
9
+ return this.ctx?.get(key);
10
10
  }
11
11
  set(key, value) {
12
- this.ctx.set(key, value);
12
+ (this.ctx ?? (this.ctx = /* @__PURE__ */ new Map())).set(key, value);
13
13
  }
14
14
  getAll() {
15
- return new Map(this.ctx);
15
+ return this.ctx ? new Map(this.ctx) : /* @__PURE__ */ new Map();
16
16
  }
17
17
  setAll(values) {
18
- this.ctx.clear();
19
- for (const [key, value] of values) this.ctx.set(key, value);
18
+ const ctx = this.ctx ?? (this.ctx = /* @__PURE__ */ new Map());
19
+ ctx.clear();
20
+ for (const [key, value] of values) ctx.set(key, value);
20
21
  }
21
22
  delete(key) {
22
- this.ctx.delete(key);
23
+ this.ctx?.delete(key);
23
24
  }
24
25
  };
25
26
 
26
- // src/CNSNeuronActivationPump.ts
27
- var CNSNeuronActivationPump = class {
28
- constructor(processor, concurrency, abortSignal, initialCapacity) {
29
- this.processor = processor;
30
- this.concurrency = concurrency;
27
+ // src/CNSStimulation.ts
28
+ var CNSDendriteContext = class {
29
+ constructor(stimulation, neuron2, abortSignal, cns) {
30
+ this.stimulation = stimulation;
31
+ this.neuron = neuron2;
31
32
  this.abortSignal = abortSignal;
32
- this.items = [];
33
- this.head = 0;
34
- this.tail = 0;
35
- this.size = 0;
36
- this.capacity = 16;
33
+ this.cns = cns;
34
+ }
35
+ get() {
36
+ return this.stimulation.getContext().get(this.neuron);
37
+ }
38
+ set(value) {
39
+ this.stimulation.getContext().set(this.neuron, value);
40
+ }
41
+ delete() {
42
+ this.stimulation.getContext().delete(this.neuron);
43
+ }
44
+ };
45
+ var CNSStimulationResponseImpl = class {
46
+ constructor(stimulation, store, inputSignal, outputSignal, queueLength, hops, error) {
47
+ this.stimulation = stimulation;
48
+ this.store = store;
49
+ this.inputSignal = inputSignal;
50
+ this.outputSignal = outputSignal;
51
+ this.queueLength = queueLength;
52
+ this.hops = hops;
53
+ this.error = error;
54
+ }
55
+ get contextValue() {
56
+ return this.store ? this.store.getAll() : /* @__PURE__ */ new Map();
57
+ }
58
+ };
59
+ var CNSStimulation = class {
60
+ constructor(cns, instanceNeuronQueue, options, onResponse) {
61
+ this.cns = cns;
62
+ this.options = options;
63
+ this.qHead = 0;
64
+ this.qTail = 0;
65
+ this.qSize = 0;
66
+ this.qCapacity = 4;
37
67
  this.activeOperations = 0;
38
- this.activeTasks = /* @__PURE__ */ new Set();
39
- // NEW: prevent re-entrant pump; defer extra runs
68
+ // Re-entrancy guard for the pump loop.
40
69
  this.pumping = false;
41
70
  this.needsPump = false;
42
- if (initialCapacity && initialCapacity > 0) {
43
- this.capacity = initialCapacity;
71
+ this.scheduledCount = 0;
72
+ this.isCompleted = false;
73
+ this.completionRejected = false;
74
+ this.ctxStore = options?.ctx;
75
+ this.instanceNeuronQueue = instanceNeuronQueue;
76
+ this.onResponse = onResponse;
77
+ if (this.options?.maxNeuronHops) {
78
+ this.nueronVisitMap = /* @__PURE__ */ new Map();
44
79
  }
45
- this.items = new Array(this.capacity);
80
+ if (this.autoCleanupContextsEnabled) {
81
+ this.activeSccCounts = /* @__PURE__ */ new Map();
82
+ }
83
+ }
84
+ pushFailedTask(failure) {
85
+ (this.failedTasks ?? (this.failedTasks = [])).push(failure);
86
+ }
87
+ finalizeResolve() {
88
+ this.completionRejected = false;
89
+ this.resolveCompleted?.();
90
+ }
91
+ finalizeReject(error) {
92
+ this.completionRejected = true;
93
+ this.completionError = error;
94
+ this.rejectCompleted?.(error);
95
+ }
96
+ /** Lazily-created neuron context store (see {@link ctxStore}). */
97
+ get ctx() {
98
+ return this.ctxStore ?? (this.ctxStore = new CNSStimulationContextStore());
46
99
  }
100
+ // ----- Inlined activation queue / pump -----
47
101
  get canStartOperation() {
48
- const limit = this.concurrency ?? Infinity;
49
- return this.activeOperations < limit && !this.abortSignal?.aborted;
50
- }
51
- resize() {
52
- const oldCapacity = this.capacity;
53
- this.capacity = oldCapacity * 2;
54
- const newItems = new Array(this.capacity);
55
- let oldIndex = this.head;
56
- for (let i = 0; i < this.size; i++) {
57
- newItems[i] = this.items[oldIndex];
102
+ const limit = this.options?.concurrency ?? Infinity;
103
+ return this.activeOperations < limit && !this.options?.abortSignal?.aborted;
104
+ }
105
+ qResize() {
106
+ const oldCapacity = this.qCapacity;
107
+ const oldItems = this.qItems;
108
+ this.qCapacity = oldCapacity * 2;
109
+ const newItems = new Array(this.qCapacity);
110
+ let oldIndex = this.qHead;
111
+ for (let i = 0; i < this.qSize; i++) {
112
+ newItems[i] = oldItems[oldIndex];
58
113
  oldIndex = (oldIndex + 1) % oldCapacity;
59
114
  }
60
- this.items = newItems;
61
- this.head = 0;
62
- this.tail = this.size;
63
- }
64
- dequeue() {
65
- if (this.size === 0) return void 0;
66
- const neuronActivationTask = this.items[this.head];
67
- this.items[this.head] = void 0;
68
- this.head = (this.head + 1) % this.capacity;
69
- this.size--;
70
- return neuronActivationTask;
115
+ this.qItems = newItems;
116
+ this.qHead = 0;
117
+ this.qTail = this.qSize;
118
+ }
119
+ qDequeue() {
120
+ if (this.qSize === 0) return void 0;
121
+ const items = this.qItems;
122
+ const task = items[this.qHead];
123
+ items[this.qHead] = void 0;
124
+ this.qHead = (this.qHead + 1) % this.qCapacity;
125
+ this.qSize--;
126
+ return task;
127
+ }
128
+ qEnqueueItem(task) {
129
+ if (!this.qItems) {
130
+ this.qItems = new Array(this.qCapacity);
131
+ } else if (this.qSize === this.qCapacity) {
132
+ this.qResize();
133
+ }
134
+ this.qItems[this.qTail] = task;
135
+ this.qTail = (this.qTail + 1) % this.qCapacity;
136
+ this.qSize++;
71
137
  }
72
- enqueueItem(neuronActivationTask) {
73
- if (this.size === this.capacity) {
74
- this.resize();
138
+ /** Enqueue a task and drive the pump unless one is already running. */
139
+ qEnqueue(task) {
140
+ this.qEnqueueItem(task);
141
+ if (!this.pumping) this.pump();
142
+ else this.needsPump = true;
143
+ }
144
+ qGetQueuedTasks() {
145
+ const result = [];
146
+ if (!this.qItems) return result;
147
+ let index = this.qHead;
148
+ for (let i = 0; i < this.qSize; i++) {
149
+ result.push(this.qItems[index]);
150
+ index = (index + 1) % this.qCapacity;
75
151
  }
76
- this.items[this.tail] = neuronActivationTask;
77
- this.tail = (this.tail + 1) % this.capacity;
78
- this.size++;
152
+ return result;
79
153
  }
80
154
  pump() {
81
155
  if (this.pumping) {
@@ -83,26 +157,26 @@ var CNSNeuronActivationPump = class {
83
157
  return;
84
158
  }
85
159
  this.pumping = true;
86
- while (this.canStartOperation && this.size > 0) {
87
- const neuronActivationTask = this.dequeue();
160
+ while (this.canStartOperation && this.qSize > 0) {
161
+ const task = this.qDequeue();
88
162
  this.activeOperations++;
89
- this.activeTasks.add(neuronActivationTask);
90
- const ret = this.processor(neuronActivationTask);
163
+ const ret = this.executeActivationTask(task);
91
164
  if (ret && typeof ret.then === "function") {
165
+ (this.activeTasks ?? (this.activeTasks = /* @__PURE__ */ new Set())).add(task);
92
166
  ret.then(
93
167
  (cb) => {
94
168
  this.activeOperations--;
95
- this.activeTasks.delete(neuronActivationTask);
169
+ this.activeTasks.delete(task);
96
170
  if (typeof cb === "function") cb();
97
- if (this.size > 0 && this.canStartOperation) {
171
+ if (this.qSize > 0 && this.canStartOperation) {
98
172
  if (this.pumping) this.needsPump = true;
99
173
  else this.pump();
100
174
  }
101
175
  },
102
176
  (err) => {
103
177
  this.activeOperations--;
104
- this.activeTasks.delete(neuronActivationTask);
105
- if (this.size > 0 && this.canStartOperation) {
178
+ this.activeTasks.delete(task);
179
+ if (this.qSize > 0 && this.canStartOperation) {
106
180
  if (this.pumping) this.needsPump = true;
107
181
  else this.pump();
108
182
  }
@@ -112,7 +186,6 @@ var CNSNeuronActivationPump = class {
112
186
  continue;
113
187
  }
114
188
  this.activeOperations--;
115
- this.activeTasks.delete(neuronActivationTask);
116
189
  if (typeof ret === "function") ret();
117
190
  }
118
191
  this.pumping = false;
@@ -121,73 +194,20 @@ var CNSNeuronActivationPump = class {
121
194
  this.pump();
122
195
  }
123
196
  }
124
- enqueue(neuronActivationTask) {
125
- this.enqueueItem(neuronActivationTask);
126
- if (!this.pumping) this.pump();
127
- else this.needsPump = true;
128
- }
129
- get length() {
130
- return this.size;
131
- }
132
- getActiveOperationsCount() {
133
- return this.activeOperations;
134
- }
135
- getQueuedTasks() {
136
- const result = [];
137
- let index = this.head;
138
- for (let i = 0; i < this.size; i++) {
139
- result.push(this.items[index]);
140
- index = (index + 1) % this.capacity;
141
- }
142
- return result;
143
- }
144
- getActiveTasks() {
145
- return Array.from(this.activeTasks);
146
- }
147
- };
148
-
149
- // src/CNSStimulation.ts
150
- var CNSStimulation = class {
151
- constructor(cns, instanceNeuronQueue, options) {
152
- this.cns = cns;
153
- this.options = options;
154
- this.scheduledCount = 0;
155
- this.pendingTasks = /* @__PURE__ */ new Set();
156
- this.failedTasks = [];
157
- this.completed = new Promise((resolve, reject) => {
158
- this.resolveCompleted = resolve;
159
- this.rejectCompleted = reject;
160
- });
161
- this.isCompleted = false;
162
- /**
163
- * Track active SCCs: SCC index -> count of active neurons in that SCC
164
- */
165
- this.activeSccCounts = /* @__PURE__ */ new Map();
166
- this.ctx = options?.ctx ?? new CNSStimulationContextStore();
167
- this.queue = new CNSNeuronActivationPump(
168
- (neuronActivationTask) => this.executeActivationTask(neuronActivationTask),
169
- options?.concurrency,
170
- options?.abortSignal
171
- );
172
- this.instanceNeuronQueue = instanceNeuronQueue;
173
- if (this.options?.maxNeuronHops) {
174
- this.nueronVisitMap = /* @__PURE__ */ new Map();
175
- }
176
- }
177
197
  tryResolveCompleted() {
178
198
  if (this.isCompleted) return;
179
- const noActive = this.queue.getActiveOperationsCount() === 0;
180
- const noPending = this.queue.length + this.scheduledCount === 0;
199
+ const noActive = this.activeOperations === 0;
200
+ const noPending = this.qSize + this.scheduledCount === 0;
181
201
  const aborted = !!this.options?.abortSignal?.aborted;
182
202
  if (noPending && noActive || aborted && noActive && !noPending) {
183
203
  if (aborted) {
184
- const queuedTasks = this.queue.getQueuedTasks();
204
+ const queuedTasks = this.qGetQueuedTasks();
185
205
  for (const task of [...queuedTasks]) {
186
- const alreadyTracked = this.failedTasks.some(
206
+ const alreadyTracked = this.failedTasks?.some(
187
207
  (ft) => ft.task === task
188
208
  );
189
209
  if (!alreadyTracked) {
190
- this.failedTasks.push({
210
+ this.pushFailedTask({
191
211
  task,
192
212
  error: new Error(
193
213
  "Task aborted - not started due to abort signal"
@@ -197,37 +217,47 @@ var CNSStimulation = class {
197
217
  }
198
218
  }
199
219
  this.isCompleted = true;
200
- this.rejectCompleted(new Error("Stimulation aborted"));
220
+ this.finalizeReject(new Error("Stimulation aborted"));
201
221
  return;
202
222
  }
203
223
  this.isCompleted = true;
204
- if (this.failedTasks.length > 0 || this.onResponseError) {
224
+ const failedCount = this.failedTasks?.length ?? 0;
225
+ if (failedCount > 0 || this.onResponseError) {
205
226
  const error = this.onResponseError || new Error(
206
- `Stimulation completed with ${this.failedTasks.length} failed task(s)`
227
+ `Stimulation completed with ${failedCount} failed task(s)`
207
228
  );
208
- this.rejectCompleted(error);
229
+ this.finalizeReject(error);
209
230
  } else {
210
- this.resolveCompleted();
231
+ this.finalizeResolve();
211
232
  }
212
233
  }
213
234
  }
214
235
  waitUntilComplete() {
236
+ if (this.completed) return this.completed;
237
+ if (this.isCompleted) {
238
+ this.completed = this.completionRejected ? Promise.reject(this.completionError) : Promise.resolve();
239
+ return this.completed;
240
+ }
241
+ this.completed = new Promise((resolve, reject) => {
242
+ this.resolveCompleted = resolve;
243
+ this.rejectCompleted = reject;
244
+ });
215
245
  return this.completed;
216
246
  }
217
247
  /**
218
248
  * Returns all current activation tasks: queued, active, and pending (scheduled but not yet enqueued)
219
249
  */
220
250
  getAllActivationTasks() {
221
- const queuedTasks = this.queue.getQueuedTasks();
222
- const activeTasks = this.queue.getActiveTasks();
223
- const pendingTasks = Array.from(this.pendingTasks);
251
+ const queuedTasks = this.qGetQueuedTasks();
252
+ const activeTasks = this.activeTasks ? Array.from(this.activeTasks) : [];
253
+ const pendingTasks = this.pendingTasks ? Array.from(this.pendingTasks) : [];
224
254
  return [...queuedTasks, ...activeTasks, ...pendingTasks];
225
255
  }
226
256
  /**
227
257
  * Returns all tasks that failed or were aborted
228
258
  */
229
259
  getFailedTasks() {
230
- return [...this.failedTasks];
260
+ return this.failedTasks ? [...this.failedTasks] : [];
231
261
  }
232
262
  /**
233
263
  * Get the context store for this stimulation
@@ -240,7 +270,7 @@ var CNSStimulation = class {
240
270
  */
241
271
  enqueueTasks(tasks) {
242
272
  for (const task of tasks) {
243
- this.queue.enqueue(task);
273
+ this.qEnqueue(task);
244
274
  }
245
275
  this.tryResolveCompleted();
246
276
  }
@@ -268,20 +298,24 @@ var CNSStimulation = class {
268
298
  * Increment the active count for the SCC containing this neuron
269
299
  */
270
300
  incrementSccCount(neuron2) {
301
+ const counts = this.activeSccCounts;
302
+ if (!counts) return;
271
303
  const sccIndex = this.cns.network.getSccIndexByNeuron(neuron2);
272
304
  if (sccIndex === void 0) return;
273
- const currentCount = this.activeSccCounts.get(sccIndex) || 0;
274
- this.activeSccCounts.set(sccIndex, currentCount + 1);
305
+ const currentCount = counts.get(sccIndex) || 0;
306
+ counts.set(sccIndex, currentCount + 1);
275
307
  }
276
308
  /**
277
309
  * Decrement the active count for the SCC containing this neuron
278
310
  */
279
311
  decrementSccCount(neuron2) {
312
+ const counts = this.activeSccCounts;
313
+ if (!counts) return;
280
314
  const sccIndex = this.cns.network.getSccIndexByNeuron(neuron2);
281
315
  if (sccIndex === void 0) return;
282
- const currentCount = this.activeSccCounts.get(sccIndex) || 0;
316
+ const currentCount = counts.get(sccIndex) || 0;
283
317
  const nextCount = Math.max(0, currentCount - 1);
284
- this.activeSccCounts.set(sccIndex, nextCount);
318
+ counts.set(sccIndex, nextCount);
285
319
  if (currentCount === 0) {
286
320
  console.warn(
287
321
  `[CNSStimulation] Attempting to decrement SCC count below 0 for neuron`
@@ -292,7 +326,8 @@ var CNSStimulation = class {
292
326
  * Check if a neuron can be guaranteed not to be visited again
293
327
  */
294
328
  canNeuronBeGuaranteedDone(neuron2) {
295
- if (!this.autoCleanupContextsEnabled) return false;
329
+ if (!this.autoCleanupContextsEnabled || !this.activeSccCounts)
330
+ return false;
296
331
  return this.cns.network.canNeuronBeGuaranteedDone(
297
332
  neuron2,
298
333
  this.activeSccCounts
@@ -300,7 +335,7 @@ var CNSStimulation = class {
300
335
  }
301
336
  cleanupCtxIfNeeded(neuron2) {
302
337
  if (this.autoCleanupContextsEnabled && this.canNeuronBeGuaranteedDone(neuron2)) {
303
- this.ctx.delete(neuron2);
338
+ this.ctxStore?.delete(neuron2);
304
339
  }
305
340
  }
306
341
  createSubscriberQueueItem(subscriber, inputSignal) {
@@ -327,11 +362,15 @@ var CNSStimulation = class {
327
362
  const subscribers = this.cns.network.getSubscribers(
328
363
  neuronActivationTask.dendriteCollateral
329
364
  );
330
- const subscriber = subscribers.find(
331
- (s) => s.neuron === neuronActivationTask.neuron
332
- );
365
+ let subscriber;
366
+ for (let i = 0; i < subscribers.length; i++) {
367
+ if (subscribers[i].neuron === neuronActivationTask.neuron) {
368
+ subscriber = subscribers[i];
369
+ break;
370
+ }
371
+ }
333
372
  if (!subscriber) {
334
- this.failedTasks.push({
373
+ this.pushFailedTask({
335
374
  task: neuronActivationTask,
336
375
  error: new Error(
337
376
  `Subscriber not found for activation task`
@@ -344,40 +383,58 @@ var CNSStimulation = class {
344
383
  const neuron2 = subscriber.neuron;
345
384
  const dendrite = subscriber.dendrite;
346
385
  const inputSignal = neuronActivationTask.input;
347
- const starter = () => {
348
- this.markNeuronActive(neuron2);
349
- let response;
350
- try {
351
- response = dendrite.response(
352
- inputSignal?.payload,
353
- neuron2.axon,
354
- {
355
- get: () => this.ctx.get(neuron2),
356
- set: (value) => this.ctx.set(neuron2, value),
357
- delete: () => this.ctx.delete(neuron2),
358
- abortSignal: this.options?.abortSignal,
359
- cns: this.cns,
360
- stimulation: this
361
- }
362
- );
363
- } catch (error) {
364
- this.markNeuronInactive(neuron2);
365
- const isAborted = this.options?.abortSignal?.aborted ?? false;
366
- this.failedTasks.push({
367
- task: neuronActivationTask,
368
- error: error instanceof Error ? error : new Error(String(error)),
369
- aborted: isAborted
370
- });
371
- this.processResponseOrResponses(
386
+ const concurrency = neuron2.concurrency;
387
+ if (concurrency === void 0 || concurrency <= 0) {
388
+ return this.runStarter(
389
+ neuron2,
390
+ dendrite,
391
+ inputSignal,
392
+ neuronActivationTask
393
+ );
394
+ }
395
+ return this.instanceNeuronQueue.run(
396
+ neuron2,
397
+ () => this.runStarter(
398
+ neuron2,
399
+ dendrite,
400
+ inputSignal,
401
+ neuronActivationTask
402
+ )
403
+ );
404
+ }
405
+ runStarter(neuron2, dendrite, inputSignal, neuronActivationTask) {
406
+ this.markNeuronActive(neuron2);
407
+ let response;
408
+ try {
409
+ response = dendrite.response(
410
+ inputSignal?.payload,
411
+ neuron2.axon,
412
+ new CNSDendriteContext(
413
+ this,
372
414
  neuron2,
373
- inputSignal,
374
- void 0,
375
- error
376
- );
377
- return () => {
378
- };
379
- }
380
- const maxDuration = neuron2.maxDuration;
415
+ this.options?.abortSignal,
416
+ this.cns
417
+ )
418
+ );
419
+ } catch (error) {
420
+ this.markNeuronInactive(neuron2);
421
+ const isAborted = this.options?.abortSignal?.aborted ?? false;
422
+ this.pushFailedTask({
423
+ task: neuronActivationTask,
424
+ error: error instanceof Error ? error : new Error(String(error)),
425
+ aborted: isAborted
426
+ });
427
+ this.processResponseOrResponses(
428
+ neuron2,
429
+ inputSignal,
430
+ void 0,
431
+ error
432
+ );
433
+ return () => {
434
+ };
435
+ }
436
+ const maxDuration = neuron2.maxDuration;
437
+ if (response instanceof Promise || maxDuration) {
381
438
  const asPromise = response instanceof Promise ? response : Promise.resolve(response);
382
439
  const timedPromise = maxDuration && maxDuration > 0 ? new Promise((resolve, reject) => {
383
440
  const t = setTimeout(() => {
@@ -397,48 +454,45 @@ var CNSStimulation = class {
397
454
  }
398
455
  );
399
456
  }) : asPromise;
400
- if (response instanceof Promise || maxDuration) {
401
- return timedPromise.then(
402
- (signal) => {
403
- return () => {
404
- this.markNeuronInactive(neuron2);
405
- return this.processResponseOrResponses(
406
- neuron2,
407
- inputSignal,
408
- signal
409
- );
410
- };
411
- },
412
- (error) => {
413
- return () => {
414
- this.markNeuronInactive(neuron2);
415
- const isAborted = this.options?.abortSignal?.aborted ?? false;
416
- this.failedTasks.push({
417
- task: neuronActivationTask,
418
- error: error instanceof Error ? error : new Error(String(error)),
419
- aborted: isAborted
420
- });
421
- return this.processResponseOrResponses(
422
- neuron2,
423
- inputSignal,
424
- void 0,
425
- error
426
- );
427
- };
428
- }
457
+ return timedPromise.then(
458
+ (signal) => {
459
+ return () => {
460
+ this.markNeuronInactive(neuron2);
461
+ return this.processResponseOrResponses(
462
+ neuron2,
463
+ inputSignal,
464
+ signal
465
+ );
466
+ };
467
+ },
468
+ (error) => {
469
+ return () => {
470
+ this.markNeuronInactive(neuron2);
471
+ const isAborted = this.options?.abortSignal?.aborted ?? false;
472
+ this.pushFailedTask({
473
+ task: neuronActivationTask,
474
+ error: error instanceof Error ? error : new Error(String(error)),
475
+ aborted: isAborted
476
+ });
477
+ return this.processResponseOrResponses(
478
+ neuron2,
479
+ inputSignal,
480
+ void 0,
481
+ error
482
+ );
483
+ };
484
+ }
485
+ );
486
+ } else {
487
+ return () => {
488
+ this.markNeuronInactive(neuron2);
489
+ return this.processResponseOrResponses(
490
+ neuron2,
491
+ inputSignal,
492
+ response
429
493
  );
430
- } else {
431
- return () => {
432
- this.markNeuronInactive(neuron2);
433
- return this.processResponseOrResponses(
434
- neuron2,
435
- inputSignal,
436
- response
437
- );
438
- };
439
- }
440
- };
441
- return this.instanceNeuronQueue.run(neuron2, starter);
494
+ };
495
+ }
442
496
  }
443
497
  processResponseOrResponses(emitter, inputSignal, outputSignalOrSignals, error) {
444
498
  if (Array.isArray(outputSignalOrSignals)) {
@@ -456,36 +510,62 @@ var CNSStimulation = class {
456
510
  processResponse(emitter, inputSignal, outputSignal, error) {
457
511
  const collateral2 = outputSignal?.collateral;
458
512
  const subscribers = collateral2 ? this.cns.network.getSubscribers(collateral2) : [];
513
+ const onResponse = this.onResponse;
514
+ if (!onResponse) {
515
+ if (collateral2 && !error) {
516
+ if (emitter) this.cleanupCtxIfNeeded(emitter);
517
+ const n = subscribers.length;
518
+ if (n > 0) {
519
+ const tasks = new Array(n);
520
+ for (let i = 0; i < n; i++) {
521
+ tasks[i] = this.createSubscriberQueueItem(
522
+ subscribers[i],
523
+ outputSignal
524
+ );
525
+ }
526
+ this.scheduledCount += n;
527
+ for (let i = 0; i < n; i++) {
528
+ this.scheduledCount--;
529
+ this.qEnqueue(tasks[i]);
530
+ }
531
+ }
532
+ }
533
+ this.tryResolveCompleted();
534
+ return;
535
+ }
459
536
  const subscriberActivationTasks = [];
460
537
  if (collateral2 && !error) {
461
538
  if (emitter) this.cleanupCtxIfNeeded(emitter);
539
+ const pending = this.pendingTasks ?? (this.pendingTasks = /* @__PURE__ */ new Set());
462
540
  for (let i = 0; i < subscribers.length; i++) {
463
541
  const task = this.createSubscriberQueueItem(
464
542
  subscribers[i],
465
543
  outputSignal
466
544
  );
467
545
  subscriberActivationTasks.push(task);
468
- this.pendingTasks.add(task);
546
+ pending.add(task);
469
547
  }
470
548
  }
471
549
  this.scheduledCount += subscriberActivationTasks.length;
472
550
  let maybePromise;
473
551
  try {
474
- maybePromise = this.options?.onResponse?.({
475
- inputSignal,
476
- outputSignal,
477
- contextValue: this.ctx.getAll(),
478
- queueLength: this.queue.length + this.scheduledCount,
479
- stimulation: this,
480
- hops: this.options?.maxNeuronHops && emitter ? this.nueronVisitMap?.get(emitter) ?? 0 : void 0,
481
- error
482
- });
552
+ maybePromise = onResponse(
553
+ new CNSStimulationResponseImpl(
554
+ this,
555
+ this.ctxStore,
556
+ inputSignal,
557
+ outputSignal,
558
+ this.qSize + this.scheduledCount,
559
+ this.options?.maxNeuronHops && emitter ? this.nueronVisitMap?.get(emitter) ?? 0 : void 0,
560
+ error
561
+ )
562
+ );
483
563
  } catch (e) {
484
564
  this.onResponseError = e instanceof Error ? e : new Error(String(e));
485
565
  for (let i = 0; i < subscriberActivationTasks.length; i++) {
486
566
  this.scheduledCount--;
487
- this.pendingTasks.delete(subscriberActivationTasks[i]);
488
- this.queue.enqueue(subscriberActivationTasks[i]);
567
+ this.pendingTasks?.delete(subscriberActivationTasks[i]);
568
+ this.qEnqueue(subscriberActivationTasks[i]);
489
569
  }
490
570
  this.tryResolveCompleted();
491
571
  return;
@@ -495,8 +575,8 @@ var CNSStimulation = class {
495
575
  () => {
496
576
  for (let i = 0; i < subscriberActivationTasks.length; i++) {
497
577
  this.scheduledCount--;
498
- this.pendingTasks.delete(subscriberActivationTasks[i]);
499
- this.queue.enqueue(subscriberActivationTasks[i]);
578
+ this.pendingTasks?.delete(subscriberActivationTasks[i]);
579
+ this.qEnqueue(subscriberActivationTasks[i]);
500
580
  }
501
581
  this.tryResolveCompleted();
502
582
  },
@@ -504,8 +584,8 @@ var CNSStimulation = class {
504
584
  this.onResponseError = error2 instanceof Error ? error2 : new Error(String(error2));
505
585
  for (let i = 0; i < subscriberActivationTasks.length; i++) {
506
586
  this.scheduledCount--;
507
- this.pendingTasks.delete(subscriberActivationTasks[i]);
508
- this.queue.enqueue(subscriberActivationTasks[i]);
587
+ this.pendingTasks?.delete(subscriberActivationTasks[i]);
588
+ this.qEnqueue(subscriberActivationTasks[i]);
509
589
  }
510
590
  this.tryResolveCompleted();
511
591
  }
@@ -514,8 +594,8 @@ var CNSStimulation = class {
514
594
  }
515
595
  for (let i = 0; i < subscriberActivationTasks.length; i++) {
516
596
  this.scheduledCount--;
517
- this.pendingTasks.delete(subscriberActivationTasks[i]);
518
- this.queue.enqueue(subscriberActivationTasks[i]);
597
+ this.pendingTasks?.delete(subscriberActivationTasks[i]);
598
+ this.qEnqueue(subscriberActivationTasks[i]);
519
599
  }
520
600
  this.tryResolveCompleted();
521
601
  }
@@ -879,8 +959,7 @@ var CNS = class {
879
959
  }
880
960
  wrapOnResponse(local) {
881
961
  if (this.globalResponseListeners.length === 0 && !local) {
882
- return () => {
883
- };
962
+ return void 0;
884
963
  }
885
964
  return (r) => {
886
965
  let anyPromise = false;
@@ -924,10 +1003,8 @@ var CNS = class {
924
1003
  const stimulation = new CNSStimulation(
925
1004
  this,
926
1005
  this.instanceNeuronQueue,
927
- {
928
- ...options,
929
- onResponse: wrapped
930
- }
1006
+ options,
1007
+ wrapped
931
1008
  );
932
1009
  stimulation.responseToSignal(signalOrSignals);
933
1010
  return stimulation;
@@ -940,10 +1017,8 @@ var CNS = class {
940
1017
  const stimulation = new CNSStimulation(
941
1018
  this,
942
1019
  this.instanceNeuronQueue,
943
- {
944
- ...options,
945
- onResponse: wrapped
946
- }
1020
+ options,
1021
+ wrapped
947
1022
  );
948
1023
  stimulation.enqueueTasks(tasks);
949
1024
  return stimulation;