Skip to content

Enable SimReady search API in agentic env gen - #982

Open
xyao-nv wants to merge 22 commits into
mainfrom
xyao/feature/sim_ready_search
Open

Enable SimReady search API in agentic env gen #982
xyao-nv wants to merge 22 commits into
mainfrom
xyao/feature/sim_ready_search

Conversation

@xyao-nv

@xyao-nv xyao-nv commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Summary

Enable SimReady search API in agentic env gen

Detailed description

  • Remove NormalizeSpec from Add SimReady search to agentic environment generation. #964. Instead it sticks to SpecInference. And objects the catalog cannot cover now carry thesimready_usd_object` registry name and are searched in the SimReady library after spec inference
  • Matching is on whole words, and the phrase's last word — the object itself — must appear in the asset path. To avoid substring matching, e.g. "bin" turns into cabinet USD.
  • Each candidate is read before it is accepted, and only assets with exactly one rigid body are kept; multi-part props are turned down with the reason recorded in the traces.
  • When nothing usable is found, the object ids are named back to the model for one further inference pass; an id already searched for is not searched again. If the replacement still cannot be spawned, the runner names the unavailable objects and shows the traces to users.
  • Opt-in, off by default: --enable_simready_search on the environment generation runner, or the "SimReady search" expander in the review GUI.

simready_droid_pick_place_cans_hammer_maple_table.yaml
image
Screenshot from 2026-07-30 22-36-30
Screenshot from 2026-07-30 22-34-57

Other examples
image
image

When Simready ones are not valid, fall back to the closest from Simready / Arena registry.

[runner] generation traces:
  simready search found no usable asset for 'pancake'
  no SimReady asset for object 'pancake'; it cannot be spawned
  asking for a replacement of: pancake

=== ArenaEnvGraphSpec (env_name='droid_pick_bagel_into_grey_bin') ===

assets:
  droid                    role=embodiment         registry_name=droid_abs_joint_pos
  maple_table              role=background         registry_name=maple_table_robolab
  bagel                    role=object             registry_name=bagel_00_objaverse_robolab
  grey_bin                 role=object             registry_name=grey_bin_robolab

[runner] generation traces:
  simready search found no usable asset for 'disinfectant spray'
  no SimReady asset for object 'disinfectant_spray'; it cannot be spawned
  asking for a replacement of: disinfectant_spray

=== ArenaEnvGraphSpec (env_name='droid_pick_soft_scrub_into_grey_bin') ===

assets:
  droid                    role=embodiment         registry_name=droid_abs_joint_pos
  maple_table              role=background         registry_name=maple_table_robolab
  soft_scrub               role=object             registry_name=soft_scrub_ycb_robolab
  grey_bin                 role=object             registry_name=grey_bin_robolab

relations:
  is_anchor        subject=maple_table
  on               subject=soft_scrub  reference=maple_table
  on               subject=grey_bin  reference=maple_table

task: composition=TaskCompositionType.ATOMIC
  description: Pick up a soft scrub cleaner from the maple table and place it into a grey bin on the table.
  [0] kind=PickAndPlaceTask

@xyao-nv
xyao-nv marked this pull request as ready for review July 31, 2026 05:01
@greptile-apps

greptile-apps Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds opt-in SimReady asset discovery to agentic environment generation.

  • Searches and ranks whole-word asset matches, rejecting assets that do not contain exactly one rigid body.
  • Adds fallback inference for unavailable objects and reports generation traces in the CLI and review GUI.
  • Registers a dynamic SimReady USD object with Physics variant-aware type and contact-sensor handling.
  • Adds the optional search dependency and coverage for search, generation, USD helpers, asset construction, and GUI behavior.

Confidence Score: 4/5

The packaging incompatibility must be fixed before merging because no supported runtime can currently use the advertised SimReady search feature.

Native uv rejects the new extra alongside either IsaacLab group due to the declared dependency conflicts, and the Docker image does not install the extra, so enabled searches return no candidates in every supported installation path.

Files Needing Attention: pyproject.toml and docker/Dockerfile.isaaclab_arena

Important Files Changed

Filename Overview
isaaclab_arena/agentic_environment_generation/environment_generation_agent.py Orchestrates SimReady resolution and one replacement-inference pass for assets that cannot be found.
isaaclab_arena/agentic_environment_generation/simready_asset_search.py Implements backend configuration, whole-word ranking, rigid-body validation, and synchronous search integration.
isaaclab_arena/assets/simready_object_library.py Registers a dynamic USD-backed object and applies the SimReady Physics variant during construction.
isaaclab_arena/utils/usd/rigid_bodies.py Adds variant-aware rigid-body inspection and caching for local or remote USD assets.
isaaclab_arena_examples/agentic_environment_generation/review_gui/generation_panel.py Adds SimReady configuration controls, configuration-sensitive agent caching, and explicit warning feedback.
pyproject.toml Adds the SimReady dependency but leaves it incompatible with both supported native simulator groups and absent from Docker.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[User prompt] --> B[Spec inference]
  B --> C{Catalog asset?}
  C -->|Yes| D[Validated Arena asset]
  C -->|No| E[SimReady search]
  E --> F{One rigid body?}
  F -->|Yes| G[Attach USD path and Physics variant]
  F -->|No| H[Name unavailable object]
  H --> I[One replacement inference pass]
  I --> B
  D --> J[Generated environment spec]
  G --> J
Loading

Reviews (1): Last reviewed commit: "fix test and uv test" | Re-trigger Greptile

Comment thread pyproject.toml Outdated
Comment on lines +131 to +138
[
{ extra = "simready" },
{ group = "isaaclab-from-wheel" },
],
[
{ extra = "simready" },
{ group = "isaaclab-from-source" },
],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 SimReady Has No Installable Runtime

When a user enables SimReady search, native uv rejects the extra alongside either supported IsaacLab group, while the Docker image installs only [dev] and therefore reaches the missing-package fallback. As a result, neither supported runtime can perform the advertised search.

Knowledge Base Used: Build, Test, and Docker Infrastructure

Comment thread isaaclab_arena/agentic_environment_generation/simready_asset_search.py Outdated
@arena-review-bot

Copy link
Copy Markdown
Contributor

🤖 Isaac Lab-Arena Review Bot

Summary

This PR adds an opt-in SimReady asset search to agentic environment generation: objects the Arena catalog can't cover are left to SimReady, searched by phrase after spec inference, filtered to whole-word matches on the object noun, and accepted only if the USD holds exactly one rigid body. It's cleanly off-by-default (CLI flag + GUI expander), keeps SimReady names/URLs out of the asset classes to avoid a pre-sim pxr import, and is well tested. Boundaries and placement look sound; my only notes are about a redundant config flag and a loose return type.

Findings

🟡 simready_asset_search.py:44SimReadySearchConfig.enabled is set in three places (constructor default, simready_search_config_from_cli, and forced via replace(..., enabled=True)) but never read. The search never checks it and the agent gates on its own enable_simready_search, so two flags encode one decision and can silently diverge. Suggest dropping the field and keeping the agent flag as the single gate.

🔵 generation_panel.py:61_simready_config_from_session returns tuple[bool, object]; callers then reach into .source, .s3_url, etc. with no type-checker help. Return tuple[bool, SimReadySearchConfig] instead.

Test Coverage

Strong. New unit tests cover word-splitting/ranking, rigid-body rejection, the search fall-through, the retry/unavailable-object flow in the agent, the registered SimReadyUsdObject, the variant-aware rigid-body helpers, and the GUI severity path. The pure-USD tests build local tmp_path stages and defer pxr into the test bodies, consistent with keeping module import safe before sim init.

Verdict

Ship it (minor cleanups optional).

@qianl-nv qianl-nv 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.

Thanks for jumping on this!

have one large size comment about how the inference calls are structured. happy to discuss in more detail.

did a quick pass on the rest. will do a more detailed review after we resolve the large refactor comment.

task:
composition: parallel
description: Pick up the pepsi can and tuna can from the maple table and place them
into the mini plastic basket, place the bean can next to the basket and the hammer

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.

the second part of the description is irrelevant, remove

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

interesting how it was picked up by the agent tho...

if spec is None:
return None, data
attempts_left = SIMREADY_RETRY_ATTEMPTS
while True:

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.

It feels like we are overloading the spec_inference call.

I'd prefer something that's a middle ground to between this and the full prompt normalization; have one optional inference call that only runs when sim-ready is enabled. It's given the prompt, the existing asset catalogue, and as to return a list of search phrase for any potentially missing assets.

This way we avoids change to existing interference path without sim-ready, and avoids this kinda hard to read loop that overloads the sim ready search query into the object spec.

Another motivation for this kind of separation of responsibility is that it'll easier to turn into a multi agent system with clear boundary.

wdyt?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

reasonable, updated



async def _configure_asset_library(config: SimReadySearchConfig, traces: list[str]) -> Any | None:
try:

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.

this is in our deps already shouldn't need to check import error

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

updated.

await library.add_s3_source(config.s3_url or ISAAC_SIMREADY_GA_S3_URL)
elif config.source == SimReadySourceKind.SERVICE:
library.add_service_source(config.service_url or DEFAULT_SIMREADY_SERVICE_URL)
elif config.source == SimReadySourceKind.CACHE:

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.

can we have just one sync bridge for library setup

    from simready.search import AssetLibrary
    library = AssetLibrary()
    if config.source in (SimReadySourceKind.ISAAC_SIM_GA, SimReadySourceKind.S3):
        asyncio.run(library.add_s3_source(config.s3_url or ISAAC_SIMREADY_GA_S3_URL))
    elif config.source == SimReadySourceKind.SERVICE:
        library.add_service_source(config.service_url or DEFAULT_SIMREADY_SERVICE_URL)
    else: 
        # log error
    return library

then we can drop all the awkward async from this file and clean it up significantly.
feels like we only need to support add_s3_source / add_service_source (remote)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Im assuming we are bumping simready as P0, and dropping "bring you own assets from S3/local".

Comment thread isaaclab_arena/assets/simready_constants.py Outdated
Comment thread isaaclab_arena/agentic_environment_generation/spec_inference.py Outdated
Comment thread isaaclab_arena/agentic_environment_generation/spec_inference.py
Comment thread isaaclab_arena/assets/simready_object_library.py Outdated
Comment thread isaaclab_arena/utils/usd/rigid_bodies.py Outdated

@qianl-nv qianl-nv 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.

Thanks for restructuring it! Add some nits. In particular, suggests clean up the EnvironmentGenerationAgent.traces usage hygiene to separate error vs info logs into separate dict entry/list under trances, then can clean up some of the ac-hoc logic in UI for trace display.

Approved, feel free to merge after address the comments.

Comment thread isaaclab_arena/agentic_environment_generation/environment_generation_agent.py Outdated
Comment thread isaaclab_arena/agentic_environment_generation/environment_generation_agent.py Outdated
Comment thread isaaclab_arena/agentic_environment_generation/environment_generation_agent.py Outdated
Comment thread isaaclab_arena/agentic_environment_generation/environment_generation_agent.py Outdated
Comment thread isaaclab_arena/agentic_environment_generation/simready_asset_search.py Outdated
Comment thread isaaclab_arena/agentic_environment_generation/simready_asset_search.py Outdated

# Reading an asset means fetching it, so only the best few hits are worth checking before we
# give up on the phrase and let the agent fall back to the Arena asset registry.
ranked = matches[: max(MAX_INSPECTED_MATCHES_PER_PHRASE, max_results)]

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.

why do we need both MAX_INSPECTED_MATCHES_PER_PHRASE and config.max_results_per_object?
can we just make sure config.max_results_per_object <=MAX_INSPECTED_MATCHES_PER_PHRASE when constructing the config? unless I misunderstand the purpose?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The two numbers measure different things:

  • max_results_per_object caps how many candidates are kept.
  • The constant floors how many hits are inspected.

Updated names & docstring to clarify.

Comment thread isaaclab_arena/tests/test_missing_object_inference.py
Comment thread isaaclab_arena/utils/usd/rigid_bodies.py Outdated
Comment thread isaaclab_arena/utils/usd/rigid_bodies.py
xyao-nv added a commit that referenced this pull request Aug 3, 2026
## Summary
Add the simready-search dependency, to unblock
#982 testing.

## Detailed description
- Override boto3, botocore, requests and s3transfer to the versions
isaacsim-kernel pins. simready-search asks for boto3==1.42.58,
requests>=2.32.5 and s3transfer 0.16.x, all over-strict; without the
overrides it does not resolve alongside either sim-stack flavor.

---------

Signed-off-by: Xinjie Yao <xyao@nvidia.com>
xyao-nv and others added 6 commits August 2, 2026 21:52
…parts

SimReady props give each part its own rigid body and hold the parts
together with fixed joints, so a spray bottle reports two bodies. Isaac
Lab expects one rigid body per rigid object and refuses to spawn them.

- Add get_physics_structure() to group rigid bodies by fixed joints.
- Use it in detect_object_type() so held-together bodies are RIGID and
  anything that can still move is ARTICULATION.
- Add weld_usd_rigid_bodies() to write a cached asset that puts the
  rigid body on a parent prim and switches off the redundant joints.
- Add apply_usd_variant_selections(), needed because SimReady props have
  no physics until the Physics variant is selected.

Signed-off-by: Xinjie Yao <xyao@nvidia.com>
The parts of a SimReady prop state their mass twice, once on the part and again on
each of its collision shapes, and the two do not always agree. Merging the parts
made PhysX read the shape figures instead of the part figures, which moved the
disinfectant bottle's centre of mass from 0.052 m to 0.082 m.

Add up the part figures during the merge and write them on the merged body, so the
prop keeps the mass, centre of mass, and inertia it had before.

Signed-off-by: Xinjie Yao <xyao@nvidia.com>
Normalize prompts before spec inference, optionally query Isaac Sim GA
SimReady props, and emit simready_usd_object candidates so generated YAML
carries concrete USD paths without per-asset registry classes.

Signed-off-by: Qian Lin <qianl@nvidia.com>
Keep prompts like "maple table" as background-only so the resting surface is the background asset itself rather than inventing an in-scene object_reference.

Signed-off-by: Qian Lin <qianl@nvidia.com>
Select the authored Physics variant when spawning SimReady USD objects and when locating rigid bodies for contact sensors, preferring body prims when multiple rigid bodies share a depth.

Signed-off-by: Qian Lin <qianl@nvidia.com>
OR path-token filters so phrases like "disinfectant bottle" still match assets whose USD paths contain only one of the words.

Signed-off-by: Qian Lin <qianl@nvidia.com>
qianl-nv and others added 16 commits August 2, 2026 21:52
Searching for a "grey bin" returned a kitchen cabinet, because
SearchFilterPathContains matches any substring and "bin" appears inside
"Cabinets". The GA library has no bin at all, so the right answer is no
result, which lets the generator fall back to the asset registry.

- Keep only results that share a whole word with the search phrase, and
  order them by how many words match.
- Split camelCase when reading a path, so sm_trashCan matches "can".
- Merge multi-part SimReady props into one rigid body when spawning, and
  detect the object type with the Physics variant selected.

Signed-off-by: Xinjie Yao <xyao@nvidia.com>
A search for a "grey bin" came back with a kitchen cabinet, which carries a
rigid body per door and cannot be picked up at all. An asset that is not one
rigid body has no business in the objects of a generated environment.

- Reject a search hit unless its USD holds exactly one RigidBodyAPI, and try
  the next hit in its place.
- Match on the last word of the search phrase, which names the object itself,
  so a grey cabinet is no longer an answer for a grey bin.
- Name the objects nothing was found for in the prompt and in the traces, so
  the agent falls back to the Arena asset registry and the user is told.
- Drop the generated droid_disinfectant_into_grey_bin environment, whose bin
  was that cabinet.

Signed-off-by: Xinjie Yao <xyao@nvidia.com>
The SimReady search now turns down any asset with more than one rigid body,
so nothing is left to merge. Remove the weld, the mass and inertia combining
it needed, the joint-based classification that decided what to merge, and the
tie-breaking that let contact sensors pick a body out of a multi-body prop.

detect_object_type goes back to raising on several rigid bodies at the same
depth, keeping only the variant selection SimReady props need.

Signed-off-by: Xinjie Yao <xyao@nvidia.com>
functools.cache cannot key on a dict of variants, which is the only reason the
read was split in two. Keep the answers in a dict of its own instead, so the
public function is the whole thing.

Signed-off-by: Xinjie Yao <xyao@nvidia.com>
The registry name is the asset library's own name, and the bucket and service
URLs say where its assets come from, so the search module is not their home.
It imports them instead, which also drops the deferred variants import.

Signed-off-by: Xinjie Yao <xyao@nvidia.com>
@xyao-nv
xyao-nv force-pushed the xyao/feature/sim_ready_search branch from 57ed713 to fe4179c Compare August 3, 2026 05:43
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