Srishti280992 commited on
Commit
75b802d
·
verified ·
1 Parent(s): 5a3bed2

Update factory/world_factory.py

Browse files
Files changed (1) hide show
  1. factory/world_factory.py +95 -11
factory/world_factory.py CHANGED
@@ -473,7 +473,28 @@ class WorldFactory:
473
  owner_agent_id: str | None = None,
474
  behavior_index: int | None = None,
475
  ) -> Behavior:
476
- """Create a runtime behavior object from a ``BehaviorSpec``."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
477
 
478
  target = self._resolve_registry_item(
479
  registry=self._behavior_registry,
@@ -489,31 +510,94 @@ class WorldFactory:
489
  behavior_index=behavior_index,
490
  )
491
 
492
- params = copy.deepcopy(spec.params)
493
- params.setdefault("id", runtime_behavior_id)
494
-
495
- behavior = self._instantiate_runtime_object(
496
- target,
497
- params,
498
- aliases={},
499
- strict=self.config.strict_constructor_params,
500
- path=f"behavior:{spec.name}.params",
501
- item_kind="behavior",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
502
  )
503
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
504
  if not isinstance(behavior, Behavior) and not callable(getattr(behavior, "execute", None)):
505
  raise RuntimeObjectBuildError(
506
  f"Behavior {spec.name!r} did not produce an executable behavior object"
507
  )
508
 
509
  self._safe_setattr(behavior, "id", runtime_behavior_id)
 
 
 
 
510
  self._safe_setattr(behavior, "name", spec.name)
 
 
 
511
  self._safe_setattr(behavior, "enabled", bool(spec.enabled))
512
  self._safe_setattr(behavior, "priority", float(spec.priority))
513
  self._safe_setattr(behavior, "tags", tuple(spec.tags))
514
  self._safe_setattr(behavior, "metadata", copy.deepcopy(spec.metadata))
515
  self._safe_setattr(behavior, "dsl_spec", spec)
516
 
 
 
 
 
 
 
 
517
  return behavior
518
 
519
  def create_policy_for_agent(self, agent_spec: AgentSpec) -> BasePolicy | None:
 
473
  owner_agent_id: str | None = None,
474
  behavior_index: int | None = None,
475
  ) -> Behavior:
476
+ """Create a runtime behavior object from a ``BehaviorSpec``.
477
+
478
+ The DSL behavior spec has this shape:
479
+
480
+ {"name": "attack", "params": {...}}
481
+
482
+ Runtime behavior objects should receive a deterministic runtime id, but
483
+ the DSL behavior name should not be passed as a constructor argument named
484
+ ``name`` because many behavior classes expose ``name`` as a read-only or
485
+ class-level registry attribute.
486
+
487
+ This method supports both behavior implementation styles used in the
488
+ codebase:
489
+
490
+ 1. Newer dataclass-style behaviors that accept params directly as
491
+ constructor kwargs.
492
+
493
+ 2. Rich core.behavior-style behaviors that expect:
494
+ Behavior(id="...", parameters={...})
495
+
496
+ The second form is especially important for rich movement/conflict modules.
497
+ """
498
 
499
  target = self._resolve_registry_item(
500
  registry=self._behavior_registry,
 
510
  behavior_index=behavior_index,
511
  )
512
 
513
+ raw_params = copy.deepcopy(spec.params)
514
+
515
+ constructor_attempts: tuple[tuple[str, dict[str, Any], bool], ...] = (
516
+ (
517
+ "direct_params",
518
+ {
519
+ **copy.deepcopy(raw_params),
520
+ "id": runtime_behavior_id,
521
+ },
522
+ self.config.strict_constructor_params,
523
+ ),
524
+ (
525
+ "parameters_dict",
526
+ {
527
+ "id": runtime_behavior_id,
528
+ "parameters": copy.deepcopy(raw_params),
529
+ },
530
+ False,
531
+ ),
532
+ (
533
+ "behavior_id_parameters_dict",
534
+ {
535
+ "behavior_id": runtime_behavior_id,
536
+ "parameters": copy.deepcopy(raw_params),
537
+ },
538
+ False,
539
+ ),
540
  )
541
 
542
+ behavior: Any | None = None
543
+ attempt_errors: list[str] = []
544
+
545
+ for attempt_name, attempt_params, strict in constructor_attempts:
546
+ try:
547
+ behavior = self._instantiate_runtime_object(
548
+ target,
549
+ attempt_params,
550
+ aliases={},
551
+ strict=strict,
552
+ path=f"behavior:{spec.name}.params",
553
+ item_kind="behavior",
554
+ )
555
+ break
556
+ except Exception as exc:
557
+ attempt_errors.append(
558
+ f"{attempt_name}: {exc.__class__.__name__}: {exc}"
559
+ )
560
+ logger.debug(
561
+ "Behavior construction attempt failed for behavior=%s attempt=%s",
562
+ spec.name,
563
+ attempt_name,
564
+ exc_info=True,
565
+ )
566
+
567
+ if behavior is None:
568
+ raise RuntimeObjectBuildError(
569
+ "Could not instantiate behavior "
570
+ f"{spec.name!r} after {len(constructor_attempts)} constructor attempt(s). "
571
+ f"Attempt errors: {attempt_errors}"
572
+ )
573
+
574
  if not isinstance(behavior, Behavior) and not callable(getattr(behavior, "execute", None)):
575
  raise RuntimeObjectBuildError(
576
  f"Behavior {spec.name!r} did not produce an executable behavior object"
577
  )
578
 
579
  self._safe_setattr(behavior, "id", runtime_behavior_id)
580
+ self._safe_setattr(behavior, "behavior_id", runtime_behavior_id)
581
+
582
+ # Do not require this to succeed. Some behavior classes expose ``name`` as
583
+ # a read-only/class-level registry attribute.
584
  self._safe_setattr(behavior, "name", spec.name)
585
+
586
+ # These are safe diagnostics/metadata attachments. They may fail on highly
587
+ # slotted/frozen classes, so _safe_setattr intentionally does not raise.
588
  self._safe_setattr(behavior, "enabled", bool(spec.enabled))
589
  self._safe_setattr(behavior, "priority", float(spec.priority))
590
  self._safe_setattr(behavior, "tags", tuple(spec.tags))
591
  self._safe_setattr(behavior, "metadata", copy.deepcopy(spec.metadata))
592
  self._safe_setattr(behavior, "dsl_spec", spec)
593
 
594
+ # Rich behavior modules such as movement.py and attack.py use
595
+ # ``self.parameters`` internally. Preserve the original DSL params there
596
+ # whenever the object supports it.
597
+ existing_parameters = getattr(behavior, "parameters", None)
598
+ if not isinstance(existing_parameters, Mapping) or not existing_parameters:
599
+ self._safe_setattr(behavior, "parameters", copy.deepcopy(raw_params))
600
+
601
  return behavior
602
 
603
  def create_policy_for_agent(self, agent_spec: AgentSpec) -> BasePolicy | None: