Evaluate Visual Coding with OpenCode
The visual_coding_opencode environment answers a question about an image over as many tool turns as the model needs. OpenCode runs each task in its own sandbox, whose shell has Python with pillow, numpy, scipy and opencv, so the model can crop, measure and plot the image and then look at what it made. A GPT judge grades the final \boxed{} answer against the gold answer.
This tutorial runs the BabyVision benchmark (388 visual-reasoning puzzles) on it.
What This Tutorial Runs
The two benchmarks have the same puzzles and answers:
babyvision_opencodeputs a visual-reasoning instruction before each question (look first, use code when the answer needs precision).babyvision_opencode_question_onlysends the image and the bare question, without the instruction, for models trained on OpenCode’s own system prompt.
Prerequisites
Complete Installation. Then check the following:
- A vision-language policy. The policy endpoint must accept image input, because the puzzle image is attached to the first user message and OpenCode’s
readtool returns the model’s crops and plots as images. - Access to Hugging Face, or a local copy of the data.
prepare.pydownloads BabyVision fromUnipatAI/BabyVision(MIT license) at a pinned revision and checks the file’s SHA-256. - An OpenAI API key for the judge, in
OPENAI_API_KEY. The judge defaults togpt-4o-minion the OpenAI API. - The sandbox image. Build it from
resources_servers/visual_coding_opencode/sandbox_image/Dockerfileand setVISUAL_CODING_OPENCODE_SANDBOX_IMAGEto it. It holds the Python image toolkit, OpenCode 1.17.11 under/opt/opencode/binand OpenCode’s plugin dependencies, each pinned by its SHA-256 in the config, because the sandbox cannot download them. - A sandbox provider. The config uses OpenSandbox: set
OPENSANDBOX_DOMAINandOPENSANDBOX_API_KEY. - A host address the sandbox can reach. OpenCode in the sandbox calls the policy model server by address. The config sets
use_absolute_ip, and only the policy model server advertises this host’s address. Every other Gym server, the judge included, sets the address127.0.0.1, so the sandbox cannot reach it. Under NeMo RL, the head server is the exception: see Train on the Environment.
The model’s shell commands run in the task’s sandbox, not on the agent host. The sandbox can reach only the policy model server’s host, on every port. This keeps the model off the internet only on an OpenSandbox server that enforces egress at the IP layer (dns+nft).
Prepare the Data
Prepare the benchmark. prepare.py downloads the 388 BabyVision tasks from Hugging Face:
On a host without internet access, download the pinned parquet file elsewhere and set BABYVISION_PARQUET to it first.
Use --benchmark babyvision_opencode_question_only for the question-only variant.
Run the Benchmark
The values below are examples. Set them to your policy endpoint and model.
The metric is mean/reward: judged accuracy over the 388 puzzles. Each task stops after 1800 seconds. A run that stops before its final answer, by timeout, output cap or context limit, scores 0. The config turns off automatic compaction, so token capture can join every model call. It sets no step limit.
To use another judge, point it at any OpenAI-compatible endpoint with ++visual_coding_opencode_judge_base_url=... and ++visual_coding_opencode_judge_model_name=....
vLLM can send every message’s content to the chat template as a list of parts. Some templates print that list’s Python representation into assistant and tool turns, and the model then copies it into its answers. If rollouts show text like [{'type': 'text', ...}], serve the model with a chat template that joins list-shaped content into text.
Read the Results
Each rollout carries the judge’s verdict and reason and the extracted answer next to reward. The judge sees the question text, the gold answer, the extracted answer and the end of the model’s text, but not the image. A response without a final answer scores 0, and so does a run that does not complete, without a judge call. A judge failure (a failed call, or a reply without a valid verdict) is not a score: the row comes back masked (failure_kind: judge_failed).
See Aggregate Metrics for the summary files a run writes.
How a Task Runs
The Environment Server runs each task as an agent session:
- It seeds the resources server, which starts the task’s sandbox from
sandbox_configand lends it to the agent. Withsandbox_network_access: model_only, the sandbox’s egress rule allows only the host ofsandbox_model_server. - It opens an
opencode_agentsession in that sandbox. The agent uploads the puzzle image into the session and attaches it withopencode run --file; the model entry declares image input, soreadalso returns images. - OpenCode works in the sandbox until it answers, the context fills or the task times out. The resources server grades the answer.
- It closes the session, and the resources server stops the sandbox.
The sandbox settings are on the resources server:
Without sandbox_provider, the resources server lends no sandbox; the agent then needs a sandbox_provider of its own.
Train on the Environment
Gym’s token capture records each model call of the session with its token IDs and log-probabilities, so the same config serves RL training. See Training on External Agent Harnesses.
The crops and plots that OpenCode’s read returns are images added between model calls. On NeMo RL’s single controller, the vLLM worker stages them, so training sees them. Gym’s local capture records them only with #5837. Saved rollouts keep the prompt image, but not the images that read returns: their tool outputs keep only text.
Under NeMo RL, the sandbox can reach Gym’s head server. NeMo RL sets the head server’s host to the node address, which is the policy host whose every port model_only opens. The head server’s /global_config_dict_yaml returns the merged config, including any key passed literally. Other environments’ servers in an RL blend that do not set 127.0.0.1 get the node address too. Allowing only the model server’s port needs a change in Gym’s core.
Reference
The component READMEs have the details:
- Visual coding resources server: the judge prompt, scoring rules, the lent sandbox and BabyVision data checks.
- OpenCode agent: sandbox sessions, prompt images and the session options.
- BabyVision benchmark: the prompt format and data preparation.