Uh oh!
There was an error while loading. Please reload this page.
Add remote Articulation backend to Gradio - #552
Conversation
Add an unauthenticated articulation-server client and make it the default Gradio backend while preserving the existing Local Codex workflow. Cover remote polling, downloads, failures, timeouts, cancellation, and backend selection with focused tests.
Greptile SummaryThe PR adds a dependency-free remote Articulation backend to the Gradio workspace while retaining Local Codex as an explicit alternative.
Confidence Score: 4/5The PR is not yet safe to merge because an in-flight status request can delay timeout reporting and cancellation beyond the configured task deadline. The polling loop checks its deadline before issuing a blocking status request, but that request retains the independent full HTTP timeout, leaving the previously reported deadline-overrun behavior outstanding. Files Needing Attention: embodichain/gen_sim/gradio_ui/app_articraft.py and embodichain/gen_sim/gradio_ui/_articulation_server_client.py
|
| Filename | Overview |
|---|---|
| embodichain/gen_sim/gradio_ui/app_articraft.py | Adds backend routing, remote task lifecycle management, bounded polling sleep, artifact handling, and Viser startup; the existing status-request deadline issue remains unresolved. |
| embodichain/gen_sim/gradio_ui/_articulation_server_client.py | Implements validated dependency-free HTTP operations for health checks, submission, status, cancellation, and atomic artifact downloads. |
| embodichain/gen_sim/gradio_ui/app_env.py | Adds remote server settings as raw strings so malformed optional values do not abort module import or Local Codex startup. |
| tests/gen_sim/gradio_ui/test_app_articraft.py | Covers backend routing, timing validation, cancellation, deadline-bounded sleep, download handling, and preview fallback behavior. |
| tests/gen_sim/gradio_ui/test_articulation_server_client.py | Exercises remote client request validation, response handling, and artifact download behavior. |
Sequence Diagram
sequenceDiagram
participant User
participant Gradio
participant Server as Articulation Server
participant Viser
User->>Gradio: Generate prompt + optional image
Gradio->>Server: Submit generation request
Server-->>Gradio: request_id
loop Until terminal state or task deadline
Gradio->>Server: Request task status
Server-->>Gradio: Current status
end
Gradio->>Server: Download completed USDC
Server-->>Gradio: USDC artifact
Gradio->>Viser: Start preview-asset process
Viser-->>User: Interactive articulation preview
Reviews (9): Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." | Re-trigger Greptile
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Pull request overview
This PR adds a dependency-free HTTP client for an articulation-server and wires it into the GenSim Gradio Articulation (Articraft) panel, making Remote server the default backend while preserving the existing Local Codex (Articraft + Codex CLI) workflow behind an explicit UI selector.
Changes:
- Add
ArticulationServerClient(urllib-based) with submit/status/cancel and atomic artifact download support. - Update
app_articraftGradio panel to route generation/configuration through either Remote server (default) or Local Codex, including session-scoped remote cancellation on reset/replacement. - Extend configuration + docs + tests to cover the new backend, environment variables, and routing behavior.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/gen_sim/gradio_ui/test_articulation_server_client.py | New unit tests validating HTTP request construction, auth header absence, and atomic downloads for the server client. |
| tests/gen_sim/gradio_ui/test_app_articraft.py | Expanded callback-level tests for backend selection, polling/download behavior, timeout/cancellation, and replacement semantics. |
| embodichain/gen_sim/gradio_ui/gradio_visualization_architecture.md | Docs updated to describe Remote server flow, env vars, and reset semantics. |
| embodichain/gen_sim/gradio_ui/app_env.py | Adds env-backed configuration for remote server base URL, request timeout, polling interval, and task timeout. |
| embodichain/gen_sim/gradio_ui/app_articraft.py | Adds backend selector + remote orchestration, status polling, cancellation registry, and updated panel wiring. |
| embodichain/gen_sim/gradio_ui/_articulation_server_client.py | New dependency-free articulation-server client implementation. |
| embodichain/gen_sim/.env.example | Documents and provides example remote server environment variables. |
| docs/source/api_reference/public_api.rst | Documents newly exported app_env settings in the public API reference. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Require finite positive values for HTTP, task, and polling timeouts so invalid nan or infinity settings cannot bypass bounded remote generation behavior.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.
Suppressed comments (4)
Previously missed (3) — in code that hasn't changed since the last review.
embodichain/gen_sim/gradio_ui/_articulation_server_client.py:128
- Artifact downloads currently reuse the default
Accept: application/jsonheader from_open(). If the server performs content negotiation, this can cause the USDC download to return JSON or an error instead of the binary artifact.
with (
self._open("GET", relative_url) as response,
temporary.open("wb") as output,
embodichain/gen_sim/.env.example:42
.env.exampledefaults the remote server URL to a private LAN IP. For an example file, a localhost default is less surprising and matches typical local deployment docs.
# Remote Articulation generation is the default UI mode.
ARTICULATION_SERVER_BASE_URL="http://192.168.3.23:18688"
ARTICULATION_SERVER_TIMEOUT_S=30
ARTICULATION_SERVER_TASK_TIMEOUT_S=7200
ARTICULATION_SERVER_POLL_INTERVAL_S=1
embodichain/gen_sim/gradio_ui/gradio_visualization_architecture.md:66
- The architecture doc uses a private LAN IP as the default
ARTICULATION_SERVER_BASE_URL. Using127.0.0.1(or wording it as an example) avoids implying this is a universally valid default.
| `ARTICULATION_SERVER_BASE_URL` | `http://192.168.3.23:18688` | 默认 Remote server 的 HTTP(S) 地址。 |
| `ARTICULATION_SERVER_TIMEOUT_S` | `30` | 单次 HTTP 请求超时。 |
| `ARTICULATION_SERVER_TASK_TIMEOUT_S` | `7200` | 服务端生成任务总等待时间。 |
embodichain/gen_sim/gradio_ui/app_env.py:99
- The default
ARTICULATION_SERVER_BASE_URLis hard-coded to a private LAN IP (192.168.3.23), which will fail for most users and can cause confusing defaults when Remote server is the UI default. Prefer a local default (or require explicit configuration).
ARTICULATION_SERVER_BASE_URL = _getenv(
"ARTICULATION_SERVER_BASE_URL", "http://192.168.3.23:18688"
)
Bound remote task logs, discard locally invalid cancellation IDs, require explicit server endpoint configuration, use artifact-appropriate Accept headers, and preserve HTTP error wrapping when response bodies are unavailable.
skywhite1024
commented
Aug 25, 2026
Addressed the Copilot review feedback in
Validation: |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Limit remote HTTP error detail reads and rendered messages, add regression coverage for oversized JSON errors, and align the architecture summary with Remote server and Local Codex output behavior.
Uh oh!
There was an error while loading. Please reload this page.
Treat empty or whitespace-only remote artifact paths as missing so the client cannot download the service root into a USDC destination. Add focused request-count regression coverage.
Uh oh!
There was an error while loading. Please reload this page.
| relative_url = artifacts.get(artifact) if isinstance(artifacts, dict) else None | ||
| if not isinstance(relative_url, str) or not relative_url.strip(): | ||
| raise ArticulationServerError( | ||
| f"task {request_id} has no artifact named {artifact!r}" | ||
| ) | ||
Keep optional articulation-server timing values unparsed during application import, then validate them only when the Remote server backend is checked or used so malformed remote settings cannot block Local Codex startup.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
embodichain/gen_sim/gradio_ui/app_articraft.py:861
- Hard-coded
300here duplicates_SERVER_LOG_LIMITand can drift if the limit changes. Prefer slicing by the constant so the cap is defined in one place.
"**Remote Articulation status check failed.**\n\n"
f"- {detail}\n"
"- The request was not retried with Local Codex.",
"\n".join(log_lines[-300:]),
"",
Check the remote task deadline before each status request and cap each polling sleep by the remaining task time so long polling intervals cannot delay timeout cancellation.
Uh oh!
There was an error while loading. Please reload this page.
Launch EmbodiChain's native Viser preview from the current Gradio Python environment after downloading a remote USDC artifact. Preserve the USDC result when preview startup fails, and cover the command, lifecycle, fallback, and documentation.
skywhite1024
commented
Aug 26, 2026
Updated in commit |
| ) | ||
| return | ||
| try: | ||
| task = client.status(request_id) |
There was a problem hiding this comment.
| def _select_available_viser_port() -> int: | ||
| """Reserve an ephemeral loopback port for a session-owned Viser preview.""" | ||
| with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as listener: | ||
| listener.bind(("127.0.0.1", 0)) | ||
| return int(listener.getsockname()[1]) |
| "**Remote Articulation request timed out and cancellation was requested.**\n\n" | ||
| f"- Request: `{request_id}`\n" | ||
| "- The request was not retried with Local Codex.", | ||
| "\n".join(log_lines[-300:]), | ||
| "", |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.
Suppressed comments (1)
embodichain/gen_sim/gradio_ui/_articulation_server_client.py:121
download()validatesrelative_url.strip()but then uses the unstripped string when constructing the request. If the server returns a relative URL with leading/trailing whitespace (e.g. " /tasks/..."), this can produce an invalid request URL and fail downloads even though the artifact is present.
relative_url = artifacts.get(artifact) if isinstance(artifacts, dict) else None
if not isinstance(relative_url, str) or not relative_url.strip():
raise ArticulationServerError(
f"task {request_id} has no artifact named {artifact!r}"
)
Uh oh!
There was an error while loading. Please reload this page.
Description
This PR adds a dependency-free articulation-server client to the GenSim Gradio workspace and makes Remote server the default Articulation generation backend. The existing Local Codex Articraft workflow, configuration, outputs, and interactive viewer remain available through an explicit UI selector.
Remote generation supports text and optional reference images, asynchronous status polling, atomic USDC downloads, clear terminal errors, bounded timeouts, and session-scoped cancellation for Reset and replacement requests. It does not send authentication headers and never silently falls back to Local Codex.
After a remote USDC download, Gradio now starts EmbodiChain's native
preview-asset --visercommand in the current Gradio Python environment and embeds the interactive viewer. A viewer startup failure does not discard the successfully generated USDC and falls back to the result summary. The Local Codex Articraft viewer path is unchanged.The deployment configuration example, architecture notes, and public API reference are updated accordingly.
Dependencies: none.
Issue: none.
Type of change
Screenshots
Not included. The focused Gradio panel construction, backend routing, viewer command, and fallback behavior are covered by automated tests.
Validation
conda run -n embodichain040 black --check --diff --color ./(815 files unchanged)PYTHONPATH="$PWD" conda run -n embodichain040 python docs/scripts/check_api_docs.py(1702/1702 exports documented)PYTHONPATH="$PWD" conda run -n embodichain040 python -m pytest tests/gen_sim/gradio_ui -q(65 passed)git diff --checkChecklist
black .formatting gate.