Skip to content

feat: Switchyard OpenCode integration#2080

Open
drifold wants to merge 6 commits into
NVIDIA-NeMo:feature/switchyard-openhands-integrationfrom
drifold:switchyard-opencode-integration
Open

feat: Switchyard OpenCode integration#2080
drifold wants to merge 6 commits into
NVIDIA-NeMo:feature/switchyard-openhands-integrationfrom
drifold:switchyard-opencode-integration

Conversation

@drifold

@drifold drifold commented Jul 20, 2026

Copy link
Copy Markdown

Stacked on #2026 (base: feature/switchyard-openhands-integration). Adds upstream opencode as a second harness for the Switchyard token-capture integration — same zero-fork principle as the OpenHands path — plus per-run Switchyard instance spawning for token injection.

What

  • Runs opencode headless (opencode run) with an opencode.json provider pointed at Switchyard — no fork, no harness modification.
  • Captures the session tree through opencode's own correlation headers: a distinct X-Session-Id per (sub)agent session, x-parent-session-id linking subagents to the root.
  • Reconstructs the root session as the main rollout and subagent sessions as token-annotated subagent_trajectories.
  • Per-run Switchyard instances: switchyard_spawn_routing_profile spawns one dedicated token-capture Switchyard instance per agent run on a free port — stateful token injection (feat: token-level capture for RL training (Switchyard ↔ NeMo Gym) Switchyard#63) requires all of a session's calls to reach one process — and reaps it after trace retrieval in run().

Zero-fork architecture

  • The opencode.json provider id is deliberately not opencode-prefixed — opencode only emits its native correlation headers for non-opencode providers; those headers are the whole capture contract.
  • Gym mints no session ids here: opencode's own ids om Switchyard's GET /v1/sessions (no harness logs
    read).
  • Title-generator side-calls (same session id, different conversation) are filtered before reconstruction.

Activation and safety

swe_agents:
  responses_api_agents:
    swe_agents:
      agent_framework: opencode
      opencode_source: opencode        # now the default; use "nv-opencode" for the fork
      switchyard_base_url: http://<host>:<port>
      # OR spawn mode (mutually exclusive with switchyard_base_url)
      # switchyard_spawn_routing_profile: /abs/path/
condition behavior
opencode_source: nv-opencode fork path (bench entrypoint)
upstream (opencode_source: opencode, now default+ subagents reconstruct
retrieval/reconstruction failure rollout kept, switchyard_trace_error set
switchyard_spawn_routing_profile absent behavichyard_base_url` or no Switchyard)
spawn mode enabled per-run instance, records under persistent_dir, instance reaped after retrieval

Changes

  • responses_api_agents/swe_agents/app.pyopencovider JSON), the opencode run command, _list_switchyard_sessions/_reconstruct_sessionssk_id steering via system-prompt instructions (works
    around an opencode quirk where it invents task_ids).
  • responses_api_agents/swe_agents/app.pyswitchyard_spawn_routing_profile / switchyard_spawn_host config (mutually exclusive
    with switchyard_base_url, validated fail-fast), specycle, agent-script build deferred until theinstance URL is known.
  • responses_api_agents/swe_agents/app.pyopenco to opencode` (upstream); config comment/docs updated
    accordingly.
  • responses_api_agents/swe_agents/configs/ — splitnch_opencode.yaml/swebench_opencode_training.yaml now target **upstream** opencode (opencode_source: gs move to swebench_nv_opencode.yaml /
    swebench_nv_opencode_training.yaml (`opencode_soured). Root README table regenerated.
  • nemo_gym/switchyard_trace.py — canonicalize toolstory-extension comparison only (opencodere-serializes compact vs. pretty-printed JSON across turns); reconstructed items keep the model's original arguments.
  • Tests: 8 new test classes across test_app.py and`, plus 7 spawn-lifecycle tests (config conflicts,session minting + script rebuild, spawn/teardown with mocked subprocess, readiness-failure reaping).

Dependencies

Requires the Switchyard side on NVIDIA-NeMo/Switchya

  • 7b33c2c (native X-Session-Id capture), be0b2c5r the opencode capture path.
  • 7f20b2a, 940b767, 8307fd9 (token-continuity ion use-case; spawn mode itself works withcapture-only).

Testing

  • 232 passed across the swe_agents and `switchyard
  • Cluster E2E (vLLM 0.24.0, Qwen3): root + subagent ode headers, both reconstruct with exact token
    fidelity, 0% masked; with token injection enabled, buous across multi-turn reasoning + tool-calling
    conversations (0 fallbacks), and an OpenHands-pattertiguity verification.

Changes from the live description are only: the openthe first two behavior-table rows (fork now keyed onnv-opencode; upstream noted as default), and two addault flip + config split). Everything else — including the - bullets, headings, dependency SHAs, and the vLs unchanged.

drifold and others added 3 commits July 20, 2026 15:00
Adds opencode_source='opencode': runs upstream opencode headless with an
opencode.json provider pointed at Switchyard (no fork), captures the
session tree via opencode's native correlation headers
(X-Session-Id / x-parent-session-id), and reconstructs root and subagent
rollouts from the retrieved sessions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: drifold <drifold@nvidia.com>
…mparison

OpenCode re-serializes tool-call arguments differently across turns (compact vs. pretty-printed JSON), which failed the message-history extension check even though the tokens were contiguous. Canonicalize arguments for the comparison only; reconstructed training items keep the model's original arguments.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: drifold <drifold@nvidia.com>
…system-prompt instructions

Signed-off-by: drifold <drifold@nvidia.com>
@copy-pr-bot

copy-pr-bot Bot commented Jul 20, 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.

@nemo-automation-bot nemo-automation-bot Bot added the community-request Issue reported or requested by someone from the community label Jul 20, 2026
Adds switchyard_spawn_routing_profile: when set, each agent run spawns one
dedicated token-capture Switchyard instance on a free port (stateful token
injection requires all of a session's calls to reach one process), scopes
records under the run's persistent_dir, and reaps the instance after trace
retrieval in run(). Mutually exclusive with switchyard_base_url; behavior
is unchanged when absent. The agent script is built after the instance URL
is known, since it embeds the Switchyard routing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: drifold <drifold@nvidia.com>
@github-actions github-actions Bot added the sla:triage-overdue Review assignment is over the one-business-day SLA label Jul 21, 2026
@svcnvidia-nemo-ci svcnvidia-nemo-ci added the waiting-on-maintainers Waiting on maintainers to respond label Jul 22, 2026
drifold and others added 2 commits July 23, 2026 09:35
…nfigs as nv-opencode

Signed-off-by: drifold <drifold@nvidia.com>
…ed context length

Fetch the served model's max_model_len from Switchyard's /v1/models (surfaced
there for token-capture routes) before building the opencode agent command,
and declare limit.context/limit.output on the generated provider entry.
Without limits, opencode requests a flat 32000 max_tokens and never compacts
(limit.context defaults to 0); with them it budgets like any registry-known
model. Output is reserved as min(32000, context // 4) so the compaction
threshold (context - output) keeps most of the window for history. Fetch
failure degrades to today's limit-less behavior with a warning.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: drifold <drifold@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community-request Issue reported or requested by someone from the community sla:triage-overdue Review assignment is over the one-business-day SLA waiting-on-maintainers Waiting on maintainers to respond

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants