Skip to content

feat: opencode agent server - #1594

Merged
cmunley1 merged 15 commits into
mainfrom
cmunley1/opencode
Jun 26, 2026
Merged

cmunley1 merged 15 commits into
mainfrom
cmunley1/opencode

Conversation

@cmunley1

Copy link
Copy Markdown
Contributor

No description provided.

cmunley1 added 4 commits June 11, 2026 11:49
Signed-off-by: Christian Munley <cmunley@nvidia.com>
Signed-off-by: Christian Munley <cmunley@nvidia.com>
Signed-off-by: Christian Munley <cmunley@nvidia.com>
Signed-off-by: Christian Munley <cmunley@nvidia.com>
@copy-pr-bot

copy-pr-bot Bot commented Jun 14, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

cmunley1 added 4 commits June 13, 2026 17:06
Signed-off-by: Christian Munley <cmunley@nvidia.com>
Signed-off-by: Christian Munley <cmunley@nvidia.com>
Signed-off-by: Christian Munley <cmunley@nvidia.com>
Signed-off-by: Christian Munley <cmunley@nvidia.com>
@cmunley1
cmunley1 marked this pull request as ready for review June 14, 2026 00:29
Signed-off-by: Christian Munley <cmunley@nvidia.com>
@cwing-nvidia cwing-nvidia linked an issue Jun 23, 2026 that may be closed by this pull request
@ananthsub
ananthsub requested a review from Glorf June 24, 2026 08:24
@anwithk anwithk moved this from Dev Todo to Review Todo in NeMo Gym 0.4.0 - July 1 Jun 25, 2026

@Glorf Glorf left a comment

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.

Added some comments which IMO are worth the change, overall the PR is well structured and in the very good shape overall

_npm_install(npm, version)

if not shutil.which("opencode"):
npm_bin_dir = subprocess.run(

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.

npm bin was removed in npm 9; the bundled Node 22.15.0 ships npm 10, so this returns empty, the PATH fix no-ops, and ensure_opencode ends in the misleading "still not on PATH" error. Use npm prefix -g (+ /bin) or npm root -g.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

addressed thanks


def model_post_init(self, __context: Any) -> None:
self.sem = Semaphore(self.config.concurrency)
ensure_opencode(self.config.opencode_version)

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.

_npm_install runs with check=True, so a transient npm/network failure raises and takes down agent construction entirely. Might be good to add some retry logic.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

addressed thanks

apiKey: ${nvidia_api_key}
models:
nvidia/qwen/qwen3-next-80b-a3b-instruct: {}
opencode_version: null

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.

parse_opencode_session reads OpenCode's private sqlite schema. With opencode_version unpinned (null = latest), an upstream release can change that schema; parsing then silently returns nothing → empty response → reward 0 with only a warning. Pin a tested version in:

  • responses_api_agents/opencode_agent/configs/opencode_agent.yaml L30 (opencode_version: null)
  • resources_servers/math_with_judge/configs/math_with_judge_opencode_agent.yaml — agent block L15–42 (no opencode_version set → also defaults to latest)

+This also might affect score reproducibility after the agent harness gets updated, so IMO it's beneficial to have this freeze in place, wdyt?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

agree, addressed by pinning, thanks

cmunley1 added 2 commits June 25, 2026 13:55
Signed-off-by: Christian Munley <cmunley@nvidia.com>
@cmunley1

Copy link
Copy Markdown
Contributor Author

/claude review

@claude claude Bot left a comment

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.

Verdict: SHIP

Clean, well-structured agent that closely follows the established claude_code_agent pattern. Cookie propagation, semaphore placement, subprocess lifecycle, config conventions, and Responses API output construction all match the repo's existing agents. No correctness, async, or API-compatibility concerns.

Two notes below (both author's-call); nothing blocking.

inner = data["opencode_agent"]["responses_api_agents"]["opencode_agent"]
assert inner["entrypoint"] == "app.py"
assert inner["concurrency"] == 8
assert inner["command"] == "opencode"

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.

NOTE — No test for _run_opencode() subprocess lifecycle.

claude_code_agent has TestRunClaudeCode (two tests) that mock asyncio.create_subprocess_exec to verify env-var wiring, command construction, timeout behavior, and workspace cleanup. This agent's parsing and utility functions are well-tested, but the subprocess path is uncovered — meaning a regression in env assembly, the --thinking flag, or the finally: shutil.rmtree cleanup would not be caught.

Not blocking since the logic is straightforward and mirrors the existing claude_code_agent, but worth adding parity when convenient.

Comment on lines +227 to +229
return
config = self._deep_merge({}, copy.deepcopy(self.config.opencode_config))
(work_dir / "opencode.json").write_text(json.dumps(config, indent=2))

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.

NOTE — _deep_merge into empty dict is a no-op; copy.deepcopy alone suffices.

_deep_merge({}, copy.deepcopy(x)) ≡ copy.deepcopy(x) — every key in override hits the else branch since base is empty, so the merge just assigns each top-level key. The deep copy already protects self.config.opencode_config from mutation.

Not wrong, just unnecessary complexity. Author's call.

Suggested change
return
config = self._deep_merge({}, copy.deepcopy(self.config.opencode_config))
(work_dir / "opencode.json").write_text(json.dumps(config, indent=2))
config = copy.deepcopy(self.config.opencode_config)

Glorf
Glorf previously approved these changes Jun 26, 2026
Signed-off-by: Christian Munley <cmunley@nvidia.com>
@cmunley1
cmunley1 merged commit fbf9725 into main Jun 26, 2026
9 checks passed
@cmunley1
cmunley1 deleted the cmunley1/opencode branch June 26, 2026 13:42
@github-project-automation github-project-automation Bot moved this from Review Todo to Done in NeMo Gym 0.4.0 - July 1 Jun 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Built-in harness integration: OpenCode

2 participants