Skip to content

Add typed configurations to Arena policies - #862

Merged
cvolkcvolk merged 7 commits into
mainfrom
cvolk/refactor/typed-policy-configs
Jul 6, 2026
Merged

Add typed configurations to Arena policies#862
cvolkcvolk merged 7 commits into
mainfrom
cvolk/refactor/typed-policy-configs

Conversation

@cvolkcvolk

@cvolkcvolk cvolkcvolk commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

Summary

Decouple policy construction from argparse

Detailed description

  • Add a generic PolicyCfg contract and limit PolicyBase to typed runtime configs.
  • Rename first-party policy configurations consistently with the Cfg convention.
  • Preserve the existing CLI through the shared dataclass-to-argparse compatibility adapter.
  • Continue the broader migration from argparse namespaces to strongly typed configurations.

@cvolkcvolk
cvolkcvolk marked this pull request as ready for review July 3, 2026 12:47
@greptile-apps

greptile-apps Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR decouples Arena policy construction from argparse by introducing a PolicyCfg base dataclass and making PolicyBase generic over it, then migrating all first-party policies to the new pattern while keeping deprecated add_args_to_parser/from_args adapters in place as a compatibility bridge.

  • PolicyBase is now PolicyBase[PolicyCfgT]; add_args_to_parser, from_args, and from_dict are removed from the base contract. A new register_policy(cfg_type=…) decorator form registers the config type so eval_runner can deserialize Job.policy_config_dict without going through argparse.
  • All first-party policy configs (ZeroActionPolicyCfg, RslRlActionPolicyCfg, ReplayActionPolicyCfg, Gr00tRemoteClosedloopPolicyCfg, Pi0RemotePolicyCfg) are renamed to the Cfg suffix and inherit PolicyCfg; the GR00T scheduler and openPI embodiment adapter are promoted into serializable config fields.
  • New tests in test_policy_cfgs.py and the updated GR00T/OpenPI test suites verify typed registration, policy construction without deserialization, and scheduler/adapter round-trips through the config.

Confidence Score: 4/5

The change is a well-scoped refactor with a clear compatibility bridge; no existing policy construction paths are broken.

Two spots use assert for runtime validation of user-supplied config data and API-misuse guards — one in the scheduler branch of Gr00tRemoteClosedloopPolicy.init and one in register_policy. Both are silently stripped by Python's optimizer, so an invalid scheduler string from a JSON job config or an incorrect decorator call could produce a confusing downstream failure rather than a clear error message. Everything else in the refactor looks correct and well-tested.

isaaclab_arena/assets/register.py (assert-based API guards) and isaaclab_arena_gr00t/policy/gr00t_remote_closedloop_policy.py (assert-based scheduler validation).

Important Files Changed

Filename Overview
isaaclab_arena/policy/policy_base.py Removed argparse abstracts (add_args_to_parser, from_args, from_dict), added PolicyCfg base dataclass and Generic[PolicyCfgT] type parameter — clean simplification.
isaaclab_arena/assets/register.py register_policy refactored to decorator factory; uses assert statements instead of exceptions for API misuse, which can be silenced by -O.
isaaclab_arena/assets/registries.py Added _cfg_types dict and register_policy/get_policy_cfg_type to PolicyRegistry; safe because SingletonMeta prevents init from running more than once.
isaaclab_arena/evaluation/eval_runner.py get_policy_from_job updated to use the registry-based typed-config path with a deprecation warning fallback to the old argparse path.
isaaclab_arena_gr00t/policy/gr00t_remote_closedloop_policy.py Scheduler selection moved from constructor parameter to config field; uses assert for validating the scheduler value at runtime.
isaaclab_arena_openpi/policy/pi0_remote_config.py Renamed Pi0RemotePolicyArgs to Pi0RemotePolicyCfg (inherits PolicyCfg); added openpi_embodiment_adapter field to make adapter selection serializable.
isaaclab_arena_openpi/policy/pi0_remote_policy.py Pi0RemotePolicy now resolves embodiment adapter from config field; removed custom from_dict override that was required by the old adapter-as-constructor-arg pattern.
isaaclab_arena/tests/test_policy_cfgs.py New test file covering typed config registration, policy construction contract, and deprecation warning for bare @register_policy.
isaaclab_arena_gr00t/policy/config/gr00t_closedloop_policy_config.py Renamed Gr00tClosedloopPolicyConfig to Gr00tClosedloopPolicyCfg; intentionally does not inherit PolicyCfg since it is an internal YAML-loaded translation config, not a PolicyBase runtime config.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant JSON as Job JSON Config
    participant ER as eval_runner
    participant PR as PolicyRegistry
    participant Cfg as PolicyCfg (typed)
    participant Policy as PolicyBase[T]

    JSON->>ER: policy_config_dict
    ER->>PR: get_policy_cfg_type(policy_cls)
    alt Typed path (preferred)
        PR-->>ER: PolicyCfgType
        ER->>Cfg: "PolicyCfgType(**policy_config_dict)"
        Cfg-->>ER: cfg instance
        ER->>Policy: policy_cls(cfg)
    else Deprecated argparse fallback
        PR-->>ER: None
        ER->>ER: DeprecationWarning
        ER->>Policy: policy_cls.from_args(parsed_args)
    end
    Policy-->>ER: policy instance
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant JSON as Job JSON Config
    participant ER as eval_runner
    participant PR as PolicyRegistry
    participant Cfg as PolicyCfg (typed)
    participant Policy as PolicyBase[T]

    JSON->>ER: policy_config_dict
    ER->>PR: get_policy_cfg_type(policy_cls)
    alt Typed path (preferred)
        PR-->>ER: PolicyCfgType
        ER->>Cfg: "PolicyCfgType(**policy_config_dict)"
        Cfg-->>ER: cfg instance
        ER->>Policy: policy_cls(cfg)
    else Deprecated argparse fallback
        PR-->>ER: None
        ER->>ER: DeprecationWarning
        ER->>Policy: policy_cls.from_args(parsed_args)
    end
    Policy-->>ER: policy instance
Loading

Reviews (1): Last reviewed commit: "Strengthen typed policy configuration te..." | Re-trigger Greptile

Comment thread isaaclab_arena_gr00t/policy/gr00t_remote_closedloop_policy.py
Comment thread isaaclab_arena/assets/register.py Outdated
Comment thread isaaclab_arena/evaluation/eval_runner.py Outdated
@arena-review-bot

Copy link
Copy Markdown
Contributor

🤖 Isaac Lab-Arena Review Bot

Summary

This PR decouples policy construction from argparse: PolicyBase becomes Generic[PolicyCfgT] over a typed PolicyCfg marker, the config_class/from_dict/add_args_to_parser/from_args contract is dropped from the base class, and the policy→config-type association moves into PolicyRegistry via @register_policy(cfg_type=...). Scheduler (GR00T) and embodiment-adapter (OpenPI) selection now live in serializable config fields so CLI and JSON construction stay equivalent. It reads as a clean, deliberate step in the argparse→typed-config migration: deprecation warnings and dated TODOs mark every transitional path, the rename to *Cfg is complete across all consumers, and boundaries hold (extensions depend on core PolicyCfg, not the reverse).

Findings

🔵 Improvement — evaluation/eval_runner.py:111 — The two consecutive if policy_cfg_type is not None: guards in get_policy_from_job are identical; the second can fold into the first for legibility (suggestion inline).

Test Coverage

Good. The new test_policy_cfgs.py verifies typed registration, that the deserialization/argparse surface is gone from PolicyBase, and that bare @register_policy still warns. The GR00T and OpenPI tests were updated to the typed constructor and add registration + scheduler/adapter-selection checks — which exercise the same policy_cls(cfg(...)) path eval_runner now uses. The typed get_policy_from_job path itself and its deprecated fallback warning are only covered indirectly; acceptable given the fallback is transitional.

Verdict

Ship it — one optional readability nit, nothing blocking.

@cvolkcvolk
cvolkcvolk force-pushed the cvolk/refactor/typed-policy-configs branch from baaf3d9 to 2316763 Compare July 3, 2026 15:26
@cvolkcvolk
cvolkcvolk changed the base branch from main to cvolk/refactor/core-environment-factory July 3, 2026 15:27

@alexmillane alexmillane left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

One question I have is, in a few places you state that there are compatibility branches to policies that don't use config classes. To me it looks as if everything has been switched over. What still remains?

Comment thread isaaclab_arena/assets/register.py Outdated
Comment thread isaaclab_arena/cli/dataclass_cli.py Outdated
Comment thread isaaclab_arena/evaluation/policy_runner_cli.py Outdated
Separate the policy runtime contract from argparse while preserving the existing CLI adapters. Make scheduler and embodiment-adapter selection part of serializable policy configs so CLI and dictionary construction remain equivalent.

Signed-off-by: Clemens Volk <cvolk@nvidia.com>
Keep the policy runtime contract limited to typed config instances. Associate config types during registration for legacy JSON evaluation and mark policy-owned argparse paths for removal.

Signed-off-by: Clemens Volk <cvolk@nvidia.com>
Keep the custom-policy guide focused on typed construction. Document the current policy_runner limitation without teaching new policies to implement deprecated argparse adapters.

Signed-off-by: Clemens Volk <cvolk@nvidia.com>
Signed-off-by: Clemens Volk <cvolk@nvidia.com>
Signed-off-by: Clemens Volk <cvolk@nvidia.com>
Reuse one dataclass-to-argparse compatibility helper for environment and policy frontends. Remove first-party policy-owned argparse adapters while preserving the deprecated untyped fallback.

Signed-off-by: Clemens Volk <cvolk@nvidia.com>
@cvolkcvolk
cvolkcvolk force-pushed the cvolk/refactor/typed-policy-configs branch from 2316763 to 5204bcd Compare July 6, 2026 13:29
@cvolkcvolk
cvolkcvolk changed the base branch from cvolk/refactor/core-environment-factory to main July 6, 2026 13:30
Signed-off-by: Clemens Volk <cvolk@nvidia.com>
@cvolkcvolk
cvolkcvolk merged commit 228ac81 into main Jul 6, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants