Skip to content
Merged
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
2 changes: 1 addition & 1 deletion fern/versions/latest/pages/about/release-notes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ New harnesses join the existing built-in set (Claude Code, Hermes, OpenHands, an
### Configure Models

- New `inference_provider` model server connects to any OpenAI-compatible hosted provider (Fireworks, Together.ai, OpenRouter, DeepInfra, Gemini, and more) with ready-made configs
- Every Gym model server now speaks the Anthropic Messages API, so Anthropic-native harnesses like the Claude Code CLI can run against any model you serve with Gym
- Every Gym model server now speaks the Anthropic Messages API, so Anthropic-native harnesses like the Claude Code CLI can run against any model you serve with Gym — see [Anthropic Messages](/model-server/anthropic-messages)

### New Benchmarks

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ position: 2

You can use an existing agent in NeMo Gym, integrate an external one, or build your own from scratch.

[`SimpleAgent`](https://github.com/NVIDIA-NeMo/Gym/tree/main/responses_api_agents/simple_agent) is a native NeMo Gym agent that handles general-purpose multi-step tool calling with configurable max steps, and works with any Resources server out of the box. NeMo Gym also includes agents that integrate external tools: for example, [`MiniSWEAgent`](https://github.com/NVIDIA-NeMo/Gym/tree/main/responses_api_agents/mini_swe_agent) wraps an external coding harness running in Docker containers and converts its output back into the NeMo Gym format.
[`SimpleAgent`](https://github.com/NVIDIA-NeMo/Gym/tree/main/responses_api_agents/simple_agent) is a native NeMo Gym agent that handles general-purpose multi-step tool calling with configurable max steps, and works with any Resources server out of the box. NeMo Gym also includes agents that integrate external tools: for example, [`MiniSWEAgent`](https://github.com/NVIDIA-NeMo/Gym/tree/main/responses_api_agents/mini_swe_agent) wraps an external coding harness running in Docker containers and converts its output back into the NeMo Gym format, and [`claude_code_agent`](https://github.com/NVIDIA-NeMo/Gym/tree/main/responses_api_agents/claude_code_agent) runs the Claude Code CLI. Because every Gym model server speaks Anthropic Messages, you can point Claude Code at any backend — see [Anthropic Messages](/model-server/anthropic-messages).

## Tools in Agent vs. Resources Server

Expand Down
137 changes: 137 additions & 0 deletions fern/versions/latest/pages/model-server/anthropic-messages.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
---
title: "Anthropic Messages"
description: "Every Gym model server exposes POST /v1/messages so Anthropic-native harnesses like Claude Code can run against any backend"
position: 8
---

Every NeMo Gym model server speaks the [Anthropic Messages API](https://docs.anthropic.com/en/api/messages) in addition to Responses and Chat Completions. That means Anthropic-native harnesses — notably the [Claude Code](https://code.claude.com/docs/en/overview) CLI — can target **any** Gym model backend (vLLM, OpenAI, Inference Providers, and so on) without a separate Anthropic proxy.

## How it works

`SimpleResponsesAPIModel` registers `POST /v1/messages` on every model server by default. The handler maps the inbound Anthropic Messages request to Gym's native Responses schema, calls that server's own `responses()` implementation (whatever upstream the server is configured for), and maps the result back to an Anthropic Messages response. When the client sets `stream: true` (Claude Code always does), the complete response is re-emitted as a synthesized Anthropic SSE event stream.

```mermaid
flowchart LR
CLI["Claude Code CLI"] -->|"POST /v1/messages"| MS["Gym model server"]
MS -->|"Messages → Responses"| R["responses()"]
R -->|"upstream call"| BE["vLLM / OpenAI / provider / …"]
BE --> R
R -->|"Responses → Messages"| MS
MS --> CLI
```

You do not configure a separate "Claude model" server. Point Claude Code at any existing Gym model server URL; the `/v1/messages` dialect is already there.

## Wire Claude Code to a Gym model server

The built-in [`claude_code_agent`](https://github.com/NVIDIA-NeMo/Gym/tree/main/responses_api_agents/claude_code_agent) runs `claude -p` as a subprocess. Set its `model_server` ref to the Gym model server you want to use. That ref takes precedence over `anthropic_base_url`: the agent resolves `ANTHROPIC_BASE_URL` to the model server, and the CLI appends `/v1/messages`.

The showcase config [`reasoning_gym_claude_code_agent_model_server.yaml`](https://github.com/NVIDIA-NeMo/Gym/blob/main/resources_servers/reasoning_gym/configs/reasoning_gym_claude_code_agent_model_server.yaml) already wires `model_server` to `policy_model`. Compose it with any model server:

```bash
gym env start \
--resources-server reasoning_gym/reasoning_gym_claude_code_agent_model_server \
--model-type vllm_model
```

This path needs only the model server's credentials (`policy_base_url`, `policy_api_key`, `policy_model_name` in `env.yaml` or as `+` overrides) — no `anthropic_*` variables.

```bash
gym eval run --no-serve \
--agent reasoning_gym_claude_code_agent_model_server \
--input resources_servers/reasoning_gym/data/example.jsonl \
--output results/claude_code_via_model_server_rollout.jsonl \
--limit 1
```

### Choose the right model type

| Model type | Upstream API | When to use |
|---|---|---|
| `vllm_model` | OpenAI-compatible **chat** (`/chat/completions`) | vLLM, NVIDIA API, most hosted chat providers |
| `openai_model` | OpenAI **Responses** (`/responses`) | OpenAI / Azure Responses endpoints only — chat-only hosts return 404 |
| `inference_provider` | Provider chat Completions | Fireworks, Together.ai, OpenRouter, and other [Inference Providers](/model-server/inference-providers) |

### Config snippet

To wire Claude Code yourself, set `model_server` on the agent and leave `anthropic_base_url` null:

```yaml
my_claude_agent:
responses_api_agents:
claude_code_agent:
entrypoint: app.py
resources_server:
type: resources_servers
name: my_verifier
model_server:
type: responses_api_models
name: policy_model
model: ${policy_model_name}
anthropic_api_key: EMPTY
anthropic_base_url: null
concurrency: 32
max_turns: 30
```

With `model_server` set, model calls go through Gym and can be recorded by [model-call capture](/model-server/model-call-capture). Direct Anthropic or `anthropic_base_url` runs bypass Gym capture.

## Call Anthropic (or another Messages endpoint) directly

If you want Claude Code to hit Anthropic's API — or any other host that already speaks `/v1/messages` — omit `model_server` and set the Anthropic credentials instead:

```yaml
# env.yaml
anthropic_api_key: sk-ant-...
anthropic_model_name: claude-sonnet-4-6
anthropic_base_url: null # null = real Anthropic API
```

For a local vLLM or Ollama endpoint that already serves Messages:

```yaml
anthropic_api_key: EMPTY
anthropic_model_name: Qwen/Qwen3-4B-Instruct-2507
anthropic_base_url: http://localhost:8000
```

<Note>
`anthropic_base_url` must **not** include `/v1`. Claude Code appends `/v1/messages` itself.
</Note>

```bash
gym env start --resources-server reasoning_gym/reasoning_gym_claude_code_agent

gym eval run --no-serve \
--agent reasoning_gym_claude_code_agent \
--input resources_servers/reasoning_gym/data/example.jsonl \
--output results/claude_code_rollout.jsonl \
--limit 1
```

## Smoke-test `/v1/messages`

Launch a model server, take its URL from the `gym env start` log (`'url': 'http://127.0.0.1:<port>'`), then:

```bash
gym env start --model-type vllm_model \
+policy_base_url=https://integrate.api.nvidia.com/v1 \
'+policy_api_key=${oc.env:NVIDIA_API_KEY}' \
+policy_model_name=meta/llama-3.1-8b-instruct

# 1. Proxy speaks Anthropic Messages (add "stream": true for the SSE path):
curl $URL/v1/messages -H 'content-type: application/json' \
-d '{"model":"x","max_tokens":64,"messages":[{"role":"user","content":"2+2?"}]}'

# 2. Real Claude Code CLI against the same server:
ANTHROPIC_BASE_URL=$URL ANTHROPIC_AUTH_TOKEN=local \
claude -p --output-format stream-json --max-turns 2 \
--model meta/llama-3.1-8b-instruct -- "What is 2+2?"
```

## Related

- Agent runtime options (`bare`, MCP, skills, thinking): [`claude_code_agent` README](https://github.com/NVIDIA-NeMo/Gym/tree/main/responses_api_agents/claude_code_agent)
- Skills evaluation pattern: [Agent Skills](/agent-server/agent-skills)
- MCP tools from a Resources Server: [MCP Resources Server](/environment-tutorials/mcp-resources-server)
- Capture model HTTP evidence: [Model-call capture](/model-server/model-call-capture)
16 changes: 15 additions & 1 deletion fern/versions/latest/pages/model-server/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ position: 1

Configure your model with the inference backend of your choice.

NeMo Gym uses the [Responses API](https://developers.openai.com/api/reference/resources/responses/methods/create) as its native schema because it natively represents tool calls, multi-turn conversations, and structured outputs. NeMo Gym provides middleware to automatically convert other protocols, for example, Chat Completions, into Responses format.
NeMo Gym uses the [Responses API](https://developers.openai.com/api/reference/resources/responses/methods/create) as its native schema because it natively represents tool calls, multi-turn conversations, and structured outputs. NeMo Gym provides middleware to automatically convert other protocolsChat Completions and Anthropic Messages — into Responses format.

For training, use a backend that returns token IDs and log probabilities (marked with <Badge minimal outlined>training</Badge> below).

Expand Down Expand Up @@ -51,3 +51,17 @@ Serve multiple request-time configs (e.g. reasoning on/off) from one Local vLLM
</Card>

</Cards>

## Protocols

Every backend above also exposes these conversion dialects on the same model server:

<Cards>

<Card title="Anthropic Messages" href="/model-server/anthropic-messages">
Run Anthropic-native harnesses like Claude Code against any Gym model server via `POST /v1/messages`.

<Badge minimal outlined>claude</Badge> <Badge minimal outlined>dialect</Badge>
</Card>

</Cards>
2 changes: 2 additions & 0 deletions responses_api_agents/claude_code_agent/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

Runs Claude Code CLI (`claude -p`) as a NeMo Gym agent server.

Docs: [Anthropic Messages](https://docs.nvidia.com/nemo/gym/main/model-server/anthropic-messages) — how every Gym model server exposes `/v1/messages`, and how to wire this agent to any `model_server`.

## Quick start

### env.yaml
Expand Down
Loading