@almadar/runtime 3.1.0 → 3.1.2
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/{OrbitalServerRuntime-QXgOGiS8.d.ts → OrbitalServerRuntime-DrZB9ksb.d.ts} +44 -17
- package/dist/OrbitalServerRuntime.d.ts +1 -1
- package/dist/OrbitalServerRuntime.js +5 -2
- package/dist/OrbitalServerRuntime.js.map +1 -1
- package/dist/{chunk-HIM4HJAN.js → chunk-KCXJNXQZ.js} +151 -40
- package/dist/chunk-KCXJNXQZ.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-HIM4HJAN.js.map +0 -1
|
@@ -403,12 +403,35 @@ function processEvent(options) {
|
|
|
403
403
|
guardResult: transition.guard ? true : void 0
|
|
404
404
|
};
|
|
405
405
|
}
|
|
406
|
+
var SINGLETON_SCOPE = "__singleton__";
|
|
407
|
+
function scopeOf(entityData) {
|
|
408
|
+
const id = entityData && entityData["id"];
|
|
409
|
+
return id ?? SINGLETON_SCOPE;
|
|
410
|
+
}
|
|
411
|
+
function compositeKey(traitName, scope) {
|
|
412
|
+
return `${traitName}::${scope}`;
|
|
413
|
+
}
|
|
406
414
|
var StateMachineManager = class {
|
|
407
415
|
traits = /* @__PURE__ */ new Map();
|
|
416
|
+
/**
|
|
417
|
+
* State map keyed by `${traitName}::${entityId | __singleton__}`.
|
|
418
|
+
*
|
|
419
|
+
* Each entity instance of an orbital gets its own copy of every
|
|
420
|
+
* trait's state machine. This is what enables N parallel subagents
|
|
421
|
+
* (one OrbitalProcess row per dispatched orbital) to all run their
|
|
422
|
+
* own Build/Validate/Fix cycle without colliding on shared trait
|
|
423
|
+
* state — the original cause of GAP-AGB-2.
|
|
424
|
+
*
|
|
425
|
+
* Initial state is created lazily on first event for each scope, so
|
|
426
|
+
* adding a trait does not pre-allocate state for every potential
|
|
427
|
+
* entity (and there's no need to know entity ids up front).
|
|
428
|
+
*/
|
|
408
429
|
states = /* @__PURE__ */ new Map();
|
|
409
430
|
config;
|
|
410
431
|
observer;
|
|
411
|
-
// Actor-model
|
|
432
|
+
// Actor-model queues, also keyed by `${traitName}::${entityId}` so
|
|
433
|
+
// each entity gets its own actor loop and concurrent subagents do
|
|
434
|
+
// not serialize through a shared queue.
|
|
412
435
|
queues = /* @__PURE__ */ new Map();
|
|
413
436
|
processing = /* @__PURE__ */ new Set();
|
|
414
437
|
constructor(traits = [], config = {}, observer) {
|
|
@@ -431,33 +454,101 @@ var StateMachineManager = class {
|
|
|
431
454
|
*/
|
|
432
455
|
addTrait(trait) {
|
|
433
456
|
this.traits.set(trait.name, trait);
|
|
434
|
-
this.states.set(trait.name, createInitialTraitState(trait));
|
|
435
457
|
}
|
|
436
458
|
/**
|
|
437
459
|
* Remove a trait from the manager.
|
|
438
460
|
*/
|
|
439
461
|
removeTrait(traitName) {
|
|
440
462
|
this.traits.delete(traitName);
|
|
441
|
-
|
|
463
|
+
const prefix = `${traitName}::`;
|
|
464
|
+
for (const key of [...this.states.keys()]) {
|
|
465
|
+
if (key.startsWith(prefix)) this.states.delete(key);
|
|
466
|
+
}
|
|
467
|
+
for (const key of [...this.queues.keys()]) {
|
|
468
|
+
if (key.startsWith(prefix)) this.queues.delete(key);
|
|
469
|
+
}
|
|
470
|
+
for (const key of [...this.processing]) {
|
|
471
|
+
if (key.startsWith(prefix)) this.processing.delete(key);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* Get-or-init the state row for a (trait, entityId) pair.
|
|
476
|
+
* Returns undefined if the trait isn't registered.
|
|
477
|
+
*/
|
|
478
|
+
getOrInitState(traitName, scope) {
|
|
479
|
+
const trait = this.traits.get(traitName);
|
|
480
|
+
if (!trait) return void 0;
|
|
481
|
+
const key = compositeKey(traitName, scope);
|
|
482
|
+
let state = this.states.get(key);
|
|
483
|
+
if (!state) {
|
|
484
|
+
state = createInitialTraitState(trait);
|
|
485
|
+
this.states.set(key, state);
|
|
486
|
+
}
|
|
487
|
+
return state;
|
|
442
488
|
}
|
|
443
489
|
/**
|
|
444
490
|
* Get current state for a trait.
|
|
491
|
+
*
|
|
492
|
+
* For single-entity orbitals, omit `entityId` — returns the singleton
|
|
493
|
+
* scope. For multi-entity orbitals (e.g. agent OrbitalSubagent), pass
|
|
494
|
+
* the entity row id to look up that specific instance's state.
|
|
445
495
|
*/
|
|
446
|
-
getState(traitName) {
|
|
447
|
-
|
|
496
|
+
getState(traitName, entityId) {
|
|
497
|
+
const scope = entityId ?? SINGLETON_SCOPE;
|
|
498
|
+
const key = compositeKey(traitName, scope);
|
|
499
|
+
const existing = this.states.get(key);
|
|
500
|
+
if (existing) return existing;
|
|
501
|
+
return this.getOrInitState(traitName, scope);
|
|
448
502
|
}
|
|
449
503
|
/**
|
|
450
|
-
* Get
|
|
504
|
+
* Get a flat traitName→state map. For multi-entity orbitals this
|
|
505
|
+
* returns one entry per trait collapsed onto the singleton scope (or
|
|
506
|
+
* the first observed scope if singleton is empty). Use
|
|
507
|
+
* `getAllStatesByScope()` to get the full per-entity view.
|
|
451
508
|
*/
|
|
452
509
|
getAllStates() {
|
|
453
|
-
|
|
510
|
+
const out = /* @__PURE__ */ new Map();
|
|
511
|
+
for (const traitName of this.traits.keys()) {
|
|
512
|
+
const singleton = this.states.get(compositeKey(traitName, SINGLETON_SCOPE));
|
|
513
|
+
if (singleton) {
|
|
514
|
+
out.set(traitName, singleton);
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
for (const [key, state] of this.states) {
|
|
518
|
+
if (key.startsWith(`${traitName}::`)) {
|
|
519
|
+
out.set(traitName, state);
|
|
520
|
+
break;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
return out;
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Get every per-entity state row, grouped by trait. Useful for
|
|
528
|
+
* inspecting parallel subagent state.
|
|
529
|
+
*/
|
|
530
|
+
getAllStatesByScope() {
|
|
531
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
532
|
+
for (const [key, state] of this.states) {
|
|
533
|
+
const sep = key.indexOf("::");
|
|
534
|
+
if (sep < 0) continue;
|
|
535
|
+
const traitName = key.slice(0, sep);
|
|
536
|
+
const scope = key.slice(sep + 2);
|
|
537
|
+
let bucket = grouped.get(traitName);
|
|
538
|
+
if (!bucket) {
|
|
539
|
+
bucket = /* @__PURE__ */ new Map();
|
|
540
|
+
grouped.set(traitName, bucket);
|
|
541
|
+
}
|
|
542
|
+
bucket.set(scope, state);
|
|
543
|
+
}
|
|
544
|
+
return grouped;
|
|
454
545
|
}
|
|
455
546
|
/**
|
|
456
547
|
* Check if a trait can handle an event from its current state.
|
|
457
548
|
*/
|
|
458
|
-
canHandleEvent(traitName, eventKey) {
|
|
549
|
+
canHandleEvent(traitName, eventKey, entityId) {
|
|
459
550
|
const trait = this.traits.get(traitName);
|
|
460
|
-
const state = this.
|
|
551
|
+
const state = this.getOrInitState(traitName, entityId ?? SINGLETON_SCOPE);
|
|
461
552
|
if (!trait || !state) return false;
|
|
462
553
|
return !!findTransition(trait, state.currentState, normalizeEventKey(eventKey));
|
|
463
554
|
}
|
|
@@ -468,9 +559,11 @@ var StateMachineManager = class {
|
|
|
468
559
|
*/
|
|
469
560
|
sendEvent(eventKey, payload, entityData) {
|
|
470
561
|
const results = [];
|
|
562
|
+
const scope = scopeOf(entityData);
|
|
471
563
|
for (const [traitName, trait] of this.traits) {
|
|
472
|
-
const traitState = this.
|
|
564
|
+
const traitState = this.getOrInitState(traitName, scope);
|
|
473
565
|
if (!traitState) continue;
|
|
566
|
+
const key = compositeKey(traitName, scope);
|
|
474
567
|
const result = processEvent({
|
|
475
568
|
traitState,
|
|
476
569
|
trait,
|
|
@@ -482,7 +575,7 @@ var StateMachineManager = class {
|
|
|
482
575
|
contextExtensions: this.config.contextExtensions
|
|
483
576
|
});
|
|
484
577
|
if (result.executed) {
|
|
485
|
-
this.states.set(
|
|
578
|
+
this.states.set(key, {
|
|
486
579
|
...traitState,
|
|
487
580
|
currentState: result.newState,
|
|
488
581
|
previousState: result.previousState,
|
|
@@ -516,31 +609,29 @@ var StateMachineManager = class {
|
|
|
516
609
|
* at a time per trait, effects fully awaited before the next event).
|
|
517
610
|
*/
|
|
518
611
|
enqueueEvent(eventKey, payload, entityData) {
|
|
612
|
+
const scope = scopeOf(entityData);
|
|
519
613
|
for (const [traitName] of this.traits) {
|
|
520
|
-
const
|
|
614
|
+
const key = compositeKey(traitName, scope);
|
|
615
|
+
const queue = this.queues.get(key) ?? [];
|
|
521
616
|
queue.push({ eventKey, payload, entityData });
|
|
522
|
-
this.queues.set(
|
|
617
|
+
this.queues.set(key, queue);
|
|
523
618
|
}
|
|
524
619
|
}
|
|
525
620
|
/**
|
|
526
|
-
* Drain a single trait's event queue, processing
|
|
527
|
-
*
|
|
528
|
-
*
|
|
529
|
-
* awaiting all effects) before the next event is dequeued. If the queue
|
|
530
|
-
* is already being drained for this trait, this call is a no-op (the
|
|
531
|
-
* running drain will pick up newly enqueued events).
|
|
532
|
-
*
|
|
533
|
-
* @param traitName - Which trait's queue to drain
|
|
534
|
-
* @param executeEffects - Async callback to run effects for a successful transition
|
|
621
|
+
* Drain a single (trait, entity) pair's event queue, processing
|
|
622
|
+
* events sequentially. Pass `entityId` to drain a specific entity
|
|
623
|
+
* instance; omit it to drain the singleton scope.
|
|
535
624
|
*/
|
|
536
|
-
async drainQueue(traitName, executeEffects) {
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
625
|
+
async drainQueue(traitName, executeEffects, entityId) {
|
|
626
|
+
const scope = entityId ?? SINGLETON_SCOPE;
|
|
627
|
+
const key = compositeKey(traitName, scope);
|
|
628
|
+
if (this.processing.has(key)) return;
|
|
629
|
+
this.processing.add(key);
|
|
630
|
+
const queue = this.queues.get(key) ?? [];
|
|
540
631
|
while (queue.length > 0) {
|
|
541
632
|
const entry = queue.shift();
|
|
542
633
|
const trait = this.traits.get(traitName);
|
|
543
|
-
const traitState = this.
|
|
634
|
+
const traitState = this.getOrInitState(traitName, scope);
|
|
544
635
|
if (!trait || !traitState) continue;
|
|
545
636
|
const result = processEvent({
|
|
546
637
|
traitState,
|
|
@@ -553,7 +644,7 @@ var StateMachineManager = class {
|
|
|
553
644
|
contextExtensions: this.config.contextExtensions
|
|
554
645
|
});
|
|
555
646
|
if (result.executed) {
|
|
556
|
-
this.states.set(
|
|
647
|
+
this.states.set(key, {
|
|
557
648
|
...traitState,
|
|
558
649
|
currentState: result.newState,
|
|
559
650
|
previousState: result.previousState,
|
|
@@ -573,35 +664,51 @@ var StateMachineManager = class {
|
|
|
573
664
|
await executeEffects(traitName, result, entry.payload);
|
|
574
665
|
}
|
|
575
666
|
}
|
|
576
|
-
this.processing.delete(
|
|
667
|
+
this.processing.delete(key);
|
|
577
668
|
}
|
|
578
669
|
/**
|
|
579
670
|
* Check whether a trait's queue is currently being drained.
|
|
580
671
|
*/
|
|
581
|
-
isProcessing(traitName) {
|
|
582
|
-
return this.processing.has(traitName);
|
|
672
|
+
isProcessing(traitName, entityId) {
|
|
673
|
+
return this.processing.has(compositeKey(traitName, entityId ?? SINGLETON_SCOPE));
|
|
583
674
|
}
|
|
584
675
|
/**
|
|
585
676
|
* Get the number of pending events in a trait's queue.
|
|
586
677
|
*/
|
|
587
|
-
getQueueLength(traitName) {
|
|
588
|
-
return this.queues.get(traitName)?.length ?? 0;
|
|
678
|
+
getQueueLength(traitName, entityId) {
|
|
679
|
+
return this.queues.get(compositeKey(traitName, entityId ?? SINGLETON_SCOPE))?.length ?? 0;
|
|
589
680
|
}
|
|
590
681
|
/**
|
|
591
682
|
* Reset a trait to its initial state.
|
|
683
|
+
*
|
|
684
|
+
* If `entityId` is provided, resets only that entity's scope.
|
|
685
|
+
* Otherwise resets every entity scope known for the trait.
|
|
592
686
|
*/
|
|
593
|
-
resetTrait(traitName) {
|
|
687
|
+
resetTrait(traitName, entityId) {
|
|
594
688
|
const trait = this.traits.get(traitName);
|
|
595
|
-
if (trait)
|
|
596
|
-
|
|
689
|
+
if (!trait) return;
|
|
690
|
+
if (entityId) {
|
|
691
|
+
this.states.set(compositeKey(traitName, entityId), createInitialTraitState(trait));
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
const prefix = `${traitName}::`;
|
|
695
|
+
for (const key of [...this.states.keys()]) {
|
|
696
|
+
if (key.startsWith(prefix)) {
|
|
697
|
+
this.states.set(key, createInitialTraitState(trait));
|
|
698
|
+
}
|
|
597
699
|
}
|
|
598
700
|
}
|
|
599
701
|
/**
|
|
600
|
-
* Reset all traits to initial states.
|
|
702
|
+
* Reset all traits to initial states (every entity scope).
|
|
601
703
|
*/
|
|
602
704
|
resetAll() {
|
|
603
705
|
for (const [traitName, trait] of this.traits) {
|
|
604
|
-
|
|
706
|
+
const prefix = `${traitName}::`;
|
|
707
|
+
for (const key of [...this.states.keys()]) {
|
|
708
|
+
if (key.startsWith(prefix)) {
|
|
709
|
+
this.states.set(key, createInitialTraitState(trait));
|
|
710
|
+
}
|
|
711
|
+
}
|
|
605
712
|
}
|
|
606
713
|
}
|
|
607
714
|
};
|
|
@@ -840,6 +947,10 @@ var EffectExecutor = class {
|
|
|
840
947
|
case "set": {
|
|
841
948
|
const [entityId, field, value] = args;
|
|
842
949
|
this.handlers.set(entityId, field, value);
|
|
950
|
+
const entity = this.bindings.entity;
|
|
951
|
+
if (entity && entity["id"] === entityId) {
|
|
952
|
+
entity[field] = value;
|
|
953
|
+
}
|
|
843
954
|
break;
|
|
844
955
|
}
|
|
845
956
|
case "persist": {
|
|
@@ -2393,5 +2504,5 @@ function parseNamespacedEvent(eventName) {
|
|
|
2393
2504
|
}
|
|
2394
2505
|
|
|
2395
2506
|
export { EffectExecutor, EventBus, HANDLER_MANIFEST, StateMachineManager, containsBindings, createContextFromBindings, createInitialTraitState, createTestExecutor, createUnifiedLoader, extractBindings, findInitialState, findTransition, getIsolatedCollectionName, getNamespacedEvent, interpolateProps, interpolateValue, isNamespacedEvent, normalizeEventKey, parseNamespacedEvent, preprocessSchema, processEvent };
|
|
2396
|
-
//# sourceMappingURL=chunk-
|
|
2397
|
-
//# sourceMappingURL=chunk-
|
|
2507
|
+
//# sourceMappingURL=chunk-KCXJNXQZ.js.map
|
|
2508
|
+
//# sourceMappingURL=chunk-KCXJNXQZ.js.map
|