Skip to content

fix: auto-detect viewer mode from global_config in rerun bridge#1435

Merged
spomichter merged 3 commits intodevfrom
fix/viewer-backend-abstraction
Mar 6, 2026
Merged

fix: auto-detect viewer mode from global_config in rerun bridge#1435
spomichter merged 3 commits intodevfrom
fix/viewer-backend-abstraction

Conversation

@spomichter
Copy link
Contributor

fixes rerun-connect not working on G1 blueprints.

problem

each blueprint had a match global_config.viewer_backend that manually mapped backend names to rerun_bridge(viewer_mode=...). the G1 primitive blueprint was missing the rerun-connect case, so dimos --viewer-backend rerun-connect run unitree-g1-sim silently created an empty autoconnect with no viewer.

fix

moved the mapping into RerunBridgeModule.start() — it now auto-detects viewer_mode from global_config.viewer_backend when not explicitly set:

  • rerunnative
  • rerun-webweb
  • rerun-connectconnect
  • nonenone

simplified both GO2 basic and G1 primitive blueprints to just:

if global_config.viewer_backend.startswith("rerun"):
    with_vis = autoconnect(rerun_bridge(**rerun_config))

no blueprint needs to know about viewer modes anymore. adding new backends only requires updating the bridge.

the rerun bridge now reads global_config.viewer_backend and maps it
to the correct viewer_mode automatically. blueprints no longer need
to match on viewer_backend and pass viewer_mode explicitly.

this fixes rerun-connect not working on the G1 blueprint (the match
statement was missing the rerun-connect case) and prevents the same
class of bug from happening when new viewer backends are added.

mapping: rerun -> native, rerun-web -> web, rerun-connect -> connect

simplified both GO2 basic and G1 primitive blueprints to just call
rerun_bridge(**rerun_config) without viewer_mode.
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 6, 2026

Greptile Summary

This PR fixes the critical bug where dimos --viewer-backend rerun-connect silently produced an empty autoconnect on G1 blueprints by centralizing the viewer_backend → viewer_mode mapping into RerunBridgeModule.start().

Key changes:

  • Config.viewer_mode defaults to None; start() auto-detects the mode from global_config.viewer_backend via the _BACKEND_TO_MODE lookup when not explicitly set.
  • Both G1 primitive and GO2 basic blueprints simplified to a single startswith("rerun") guard — no more per-blueprint viewer mode branching.
  • The standalone run_bridge() / dimos rerun-bridge CLI path remains unaffected (still passes viewer_mode explicitly and bypasses auto-detection).

The fix is targeted, removes duplication, and ensures every blueprint automatically gets the correct viewer mode regardless of backend. Verified that blueprint guards prevent hypothetical fallback issues.

Confidence Score: 5/5

  • Safe to merge — the fix is correct, targeted, and removes per-blueprint duplication without introducing new issues.
  • The PR successfully fixes the concrete bug (rerun-connect missing on G1) by centralizing the viewer_backend mapping. Code paths are protected by blueprint guards (startswith("rerun") checks). The auto-detection logic is sound: known backends map to known modes, and the fallback only triggers with explicit instantiation in non-guarded contexts (which don't occur today). The fix simplifies both blueprints and makes the system more maintainable for future backends.
  • No files require special attention

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["dimos --viewer-backend backend"] --> B["Blueprint loaded - G1 or GO2"]
    B --> C{viewer_backend\n== foxglove?}
    C -- Yes --> D["autoconnect(foxglove_bridge())"]
    C -- No --> E{viewer_backend\nstarts with rerun?}
    E -- No --> F["autoconnect() or _transports_base\nno visualization"]
    E -- Yes --> G["autoconnect(rerun_bridge)\nviewer_mode=None"]
    G --> H["RerunBridgeModule.start()"]
    H --> I{config.viewer_mode\nis None?}
    I -- No --> L["Use explicit viewer_mode"]
    I -- Yes --> J["_BACKEND_TO_MODE.get\nglobal_config.viewer_backend\nfallback: native"]
    J --> K["Set self.config.viewer_mode"]
    K --> L
    L --> M{viewer_mode?}
    M -- native --> N["rr.spawn() - desktop viewer"]
    M -- web --> O["rr.serve_grpc + serve_web_viewer"]
    M -- connect --> P["rr.connect_grpc(connect_url)"]
    M -- none --> Q["rr.init only - headless"]
Loading

Last reviewed commit: c8e30c6

…rocess

the previous approach read global_config.viewer_backend inside start() which
runs in a forkserver worker process. the forkserver is created before the CLI
applies --viewer-backend, so workers always saw the default (rerun-web).

now: Config.viewer_mode uses default_factory=_resolve_viewer_mode which reads
global_config at blueprint construction time in the main process. the resolved
value is baked into the Config before being serialized to the worker.
default_factory runs when Config is instantiated inside the worker process,
not at blueprint creation time. the kwargs dict is what gets serialized to
the worker, so viewer_mode must be in the kwargs.

call _resolve_viewer_mode() at module-level (main process) and pass the
result as viewer_mode= to rerun_bridge().
@spomichter spomichter merged commit 68671b9 into dev Mar 6, 2026
12 checks passed
@spomichter spomichter deleted the fix/viewer-backend-abstraction branch March 6, 2026 11:28
mustafab0 pushed a commit that referenced this pull request Mar 6, 2026
* fix: auto-detect viewer mode from global_config in rerun bridge

the rerun bridge now reads global_config.viewer_backend and maps it
to the correct viewer_mode automatically. blueprints no longer need
to match on viewer_backend and pass viewer_mode explicitly.

this fixes rerun-connect not working on the G1 blueprint (the match
statement was missing the rerun-connect case) and prevents the same
class of bug from happening when new viewer backends are added.

mapping: rerun -> native, rerun-web -> web, rerun-connect -> connect

simplified both GO2 basic and G1 primitive blueprints to just call
rerun_bridge(**rerun_config) without viewer_mode.

* fix: resolve viewer_mode at config construction time, not in worker process

the previous approach read global_config.viewer_backend inside start() which
runs in a forkserver worker process. the forkserver is created before the CLI
applies --viewer-backend, so workers always saw the default (rerun-web).

now: Config.viewer_mode uses default_factory=_resolve_viewer_mode which reads
global_config at blueprint construction time in the main process. the resolved
value is baked into the Config before being serialized to the worker.

* fix: pass viewer_mode explicitly in blueprint kwargs

default_factory runs when Config is instantiated inside the worker process,
not at blueprint creation time. the kwargs dict is what gets serialized to
the worker, so viewer_mode must be in the kwargs.

call _resolve_viewer_mode() at module-level (main process) and pass the
result as viewer_mode= to rerun_bridge().
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.

1 participant