Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 67 additions & 36 deletions src/openenv/core/env_server/web_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -557,47 +557,18 @@ async def web_state():
quick_start_md = get_quick_start_markdown(metadata, action_cls, observation_cls)

display_title = title_override or get_gradio_display_title(metadata)
default_blocks = build_gradio_app(
gradio_blocks = _build_gradio_blocks(
web_manager,
action_fields,
metadata,
is_chat_env,
title=metadata.name,
quick_start_md=quick_start_md,
quick_start_md,
display_title=display_title,
gradio_builder=gradio_builder,
custom_tab_name=custom_tab_name,
custom_tab_primary=custom_tab_primary,
show_default_tab=show_default_tab,
)
default_blocks.title = display_title
if gradio_builder is not None:
custom_blocks = gradio_builder(
web_manager,
action_fields,
metadata,
is_chat_env,
display_title,
quick_start_md,
)
if not isinstance(custom_blocks, gr.Blocks):
raise TypeError(
f"gradio_builder must return a gr.Blocks instance, "
f"got {type(custom_blocks).__name__}"
)
if not show_default_tab:
# No TabbedInterface wrapper to carry the app title.
custom_blocks.title = display_title
gradio_blocks = custom_blocks
else:
if custom_tab_primary:
tab_blocks = [custom_blocks, default_blocks]
tab_labels = [custom_tab_name, "Playground"]
else:
tab_blocks = [default_blocks, custom_blocks]
tab_labels = ["Playground", custom_tab_name]
gradio_blocks = gr.TabbedInterface(
tab_blocks,
tab_names=tab_labels,
title=display_title,
)
else:
gradio_blocks = default_blocks
app = gr.mount_gradio_app(
app,
gradio_blocks,
Expand All @@ -609,6 +580,66 @@ async def web_state():
return app


def _build_gradio_blocks(
web_manager: WebInterfaceManager,
action_fields: List[Dict[str, Any]],
metadata: EnvironmentMetadata,
is_chat_env: bool,
quick_start_md: str,
*,
display_title: str,
gradio_builder: Optional[Callable[..., Any]],
custom_tab_name: str,
custom_tab_primary: bool,
show_default_tab: bool,
) -> gr.Blocks:
"""Build the Gradio block tree mounted at `/web`."""
default_blocks = build_gradio_app(
web_manager,
action_fields,
metadata,
is_chat_env,
title=metadata.name,
quick_start_md=quick_start_md,
)
default_blocks.title = display_title

if gradio_builder is None:
return default_blocks

custom_blocks = gradio_builder(
web_manager,
action_fields,
metadata,
is_chat_env,
display_title,
quick_start_md,
)
if not isinstance(custom_blocks, gr.Blocks):
raise TypeError(
f"gradio_builder must return a gr.Blocks instance, "
f"got {type(custom_blocks).__name__}"
)

if not show_default_tab:
# No TabbedInterface wrapper to carry the app title.
custom_blocks.title = display_title
return custom_blocks

if custom_tab_primary:
tab_blocks = [custom_blocks, default_blocks]
tab_labels = [custom_tab_name, "Playground"]
else:
tab_blocks = [default_blocks, custom_blocks]
tab_labels = ["Playground", custom_tab_name]

return gr.TabbedInterface(
tab_blocks,
tab_names=tab_labels,
title=display_title,
)


def _is_chat_env(action_cls: Type[Action]) -> bool:
"""Return True if the action class is a chat-style env (tokens field)."""
if hasattr(action_cls, "model_fields"):
Expand Down
29 changes: 29 additions & 0 deletions tests/core/test_web_interface_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,35 @@ def builder(web_manager, action_fields, metadata, is_chat_env, title, quick_star
assert captured["blocks"].title == "Tabbed Layout"


def test_custom_builder_defaults_to_playground_first(monkeypatch) -> None:
captured = _capture_mounted_blocks(monkeypatch)

def fake_tabbed_interface(blocks, tab_names, title):
captured["tab_blocks"] = blocks
captured["tab_names"] = tab_names
captured["tab_title"] = title
return gr.Blocks(title=title)

monkeypatch.setattr(web_interface.gr, "TabbedInterface", fake_tabbed_interface)

def builder(web_manager, action_fields, metadata, is_chat_env, title, quick_start):
return gr.Blocks(title=title)

create_web_interface_app(
LayoutEnvironment,
LayoutAction,
LayoutObservation,
env_name="layout_env",
gradio_builder=builder,
custom_tab_name="Custom View",
title_override="Tabbed Layout",
)

assert captured["tab_names"] == ["Playground", "Custom View"]
assert captured["tab_title"] == "Tabbed Layout"
assert len(captured["tab_blocks"]) == 2


def test_title_override_applies_without_custom_builder(monkeypatch) -> None:
captured = _capture_mounted_blocks(monkeypatch)

Expand Down