Spaces:
Runtime error
Runtime error
Update factory/world_factory.py
Browse files- 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 |
-
|
| 493 |
-
|
| 494 |
-
|
| 495 |
-
|
| 496 |
-
|
| 497 |
-
|
| 498 |
-
|
| 499 |
-
|
| 500 |
-
|
| 501 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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:
|