Skip to content

feat: Add protocol-driven GR00T inference compatibility#5

Merged
yinsong1986 merged 3 commits intostrands-labs:mainfrom
eraykeskinmac:feat/groot-n1d6-support
Mar 30, 2026
Merged

feat: Add protocol-driven GR00T inference compatibility#5
yinsong1986 merged 3 commits intostrands-labs:mainfrom
eraykeskinmac:feat/groot-n1d6-support

Conversation

@eraykeskinmac
Copy link
Copy Markdown
Contributor

@eraykeskinmac eraykeskinmac commented Mar 21, 2026

Summary

Add multi-protocol support for the GR00T policy client, enabling communication with both Gr00tSimPolicyWrapper servers (Isaac-GR00T N1.6+) and direct policy servers (N1.5).

Problem

Isaac-GR00T N1.6 changed the server-side inference protocol: video observations require a temporal dimension (B,T,H,W,C), state values must be float32, requests must be wrapped in {"observation": obs}, and action responses include a batch dimension. The existing client only supports the older format, causing inference failures with newer servers.

Approach

Data configs are unchanged. The original key mappings (video, state, action, language) work with both protocols. Only the transport-level formatting differs — this is handled by a new PROTOCOLS registry:

Protocol Video State dtype Request Response Used by
sim_wrapper 5D (B,T,H,W,C) float32 {"observation": obs} (B,T,dim) N1.6+ SimPolicyWrapper
direct 4D (B,H,W,C) float64 flat dict (T,dim) N1.5 direct policy

Adding future protocols requires only a new entry in PROTOCOLS — no changes to Gr00tPolicy or data configs.

Changes

File What changed
data_config.py Add PROTOCOLS registry. Add protocol field to libero configs. Original config keys untouched.
__init__.py Single _build_observation() adapts to protocol. Batch dim stripping for responses.
client.py Protocol-aware request wrapping with auto-detection fallback.
tests/test_groot_n1d6.py 26 tests: config integrity, observation formatting, action conversion, protocol selection.

Backward compatibility

  • All original data configs preserved exactly (verified by test_original_configs_unchanged)
  • groot_version="n1d6" kwarg still works (maps to protocol="sim_wrapper")
  • Configs without protocol field default to auto-detection
  • All 11 existing tests pass unchanged

Usage

# Protocol auto-resolved from config (recommended)
policy = create_policy(provider="groot", data_config="libero", host="localhost", port=5556)

# Explicit override
policy = create_policy(provider="groot", data_config="libero:sim_wrapper", ...)
policy = create_policy(provider="groot", data_config="libero:direct", ...)

Test results

  • 37 tests pass (26 new + 11 existing, zero regressions)
  • Lint clean (black, isort, flake8)
  • Real GR00T N1.6 server on AWS g5.xlarge (A10G 24GB GPU):
    • 3/3 Libero spatial tasks completed with reward=1.0
    • 0xAnkitSingh/GR00T-N1.6-LIBERO checkpoint

@eraykeskinmac eraykeskinmac force-pushed the feat/groot-n1d6-support branch 2 times, most recently from 21b9126 to bcbd518 Compare March 21, 2026 01:58
@eraykeskinmac eraykeskinmac changed the title feat: Add GR00T N1.6 (Isaac-GR00T N1D6) compatibility feat: Add protocol-driven GR00T inference compatibility Mar 21, 2026
Adapt the GR00T policy client to work with both sim_wrapper
(Isaac-GR00T N1.6+ Gr00tSimPolicyWrapper) and direct (N1.5)
server protocols.

Key design: data configs are UNCHANGED — they describe WHAT keys
to use. A new PROTOCOLS registry describes HOW to format and send
observations (video shape, state dtype, request wrapping). Protocol
is resolved from the config or overridden at runtime.

Changes:
- data_config.py: Add PROTOCOLS registry and protocol field to
  libero configs. All original configs preserved exactly as-is.
- __init__.py: Single _build_observation() adapts video dims,
  state dtype, language format based on active protocol. Flexible
  action parsing handles both response formats.
- client.py: Protocol-aware request wrapping with auto-detection.
- tests/test_groot_n1d6.py: 26 tests covering config integrity,
  observation formatting, action conversion, protocol selection.

Tested with real GR00T N1.6 server (A10G GPU):
  3/3 Libero spatial tasks completed (reward=1.0)
@eraykeskinmac eraykeskinmac force-pushed the feat/groot-n1d6-support branch from bcbd518 to 7a3e33e Compare March 21, 2026 02:16
@eraykeskinmac
Copy link
Copy Markdown
Contributor Author

@cagataycali Hey! Could you review this PR when you get a chance? 🙏

Copy link
Copy Markdown
Contributor

@yinsong1986 yinsong1986 left a comment

Choose a reason for hiding this comment

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

PR #5 — feat: Add protocol-driven GR00T inference compatibility

Summary: Adds a two-protocol dispatch layer (sim_wrapper / direct) to the GR00T policy client so it can communicate with both Isaac-GR00T N1.5 and N1.6 servers without changing data configs.


🟡 Suggestions (non-blocking)

  • [__init__.py / _map_libero_state] The original code had an explicit else branch that zeroed out all state keys when robot0_eef_pos/robot0_eef_quat were missing. The new version drops it — if those keys are absent, state entries are never added to obs. Worth restoring as a defensive fallback.

  • [client.py / get_action auto-detect] _request never raises on a malformed response, so the except RuntimeError fallback to direct will never trigger in practice. Consider validating the response shape/structure and falling back on that instead.

  • [__init__.py / _create_fallback_actions] Fallback now returns np.zeros((h, 1)) for every key regardless of actual action dimensionality. Worth restoring per-key dim inference from key names (joint_pos→7, eef_pos→3, etc.).

  • [__init__.py / _add_video_dims] reshape(1, 1, *image.shape) assumes input is always (H, W, C). An assert image.ndim == 3 before the reshape would catch edge cases early.

  • [data_config.py / _lookup] Fuzzy libero match + protocol override precedence is implicit — a short comment would help future readers.

  • [tests/test_groot_n1d6.py] Consider mocking GR00TClient in tests that instantiate Gr00tPolicy to make isolation explicit.


✅ Verdict

Needs changes (minor) — solid, well-structured work with good test coverage and clean backward compatibility. A few small defensive gaps worth addressing.

- _map_libero_state: zero-fill state when eef_pos/eef_quat missing
- client.py auto-detect: validate response structure via _has_action_keys
- _create_fallback_actions: infer per-key dims from key names
- _add_video_dims: assert image.ndim == 3 for early error detection
- _resize_image: ensure 3-D output in exception fallback path
- _lookup: add docstring with resolution order and override semantics
- tests: patch GR00TClient to avoid real ZMQ sockets, add 5 new tests

35/35 tests passing.
@eraykeskinmac eraykeskinmac force-pushed the feat/groot-n1d6-support branch from 8b410e6 to 4bc4063 Compare March 24, 2026 21:03
@yinsong1986
Copy link
Copy Markdown
Contributor

Creating environment: default
Installing project in development mode
Checking dependencies
Syncing dependencies
cmd [1] | black --check strands_robots_sim tests
would reformat /home/runner/work/robots-sim/robots-sim/strands_robots_sim/policies/groot/client.py
would reformat /home/runner/work/robots-sim/robots-sim/strands_robots_sim/policies/groot/__init__.py
would reformat /home/runner/work/robots-sim/robots-sim/tests/test_groot_n1d6.py

FYI: @eraykeskinmac failing the lint test. Thanks!

@yinsong1986 yinsong1986 self-requested a review March 28, 2026 04:58
@yinsong1986 yinsong1986 merged commit 6e7861d into strands-labs:main Mar 30, 2026
2 checks passed
@eraykeskinmac eraykeskinmac deleted the feat/groot-n1d6-support branch March 31, 2026 08:14
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