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
4 changes: 3 additions & 1 deletion responses_api_agents/opencode_agent/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,9 @@ def _build_opencode_config(self, rollout_id: Optional[str] = None) -> dict[str,
model,
{
"name": self.config.model,
"interleaved": {"field": "reasoning"},
# Gym model servers emit and accept `reasoning_content`; OpenCode replays assistant
# history under this field, and Gym rejects an unknown `reasoning` key with a 422.
"interleaved": {"field": "reasoning_content"},
"limit": {"context": self.config.context_window, "output": self.config.max_output_tokens},
},
)
Expand Down
25 changes: 25 additions & 0 deletions responses_api_agents/opencode_agent/tests/test_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

from nemo_gym.config_types import ModelServerRef, ResourcesServerRef
from nemo_gym.openai_utils import (
NeMoGymChatCompletionCreateParamsNonStreaming,
NeMoGymEasyInputMessage,
NeMoGymFunctionCallOutput,
NeMoGymResponseCreateParamsNonStreaming,
Expand Down Expand Up @@ -391,6 +392,30 @@ def test_model_server_builds_local_provider(self) -> None:
assert provider["options"]["baseURL"] == "http://model/v1"
assert provider["models"]["Qwen3.6-35B-A3B"]["limit"]["output"] == 131072

def test_model_server_replayed_reasoning_is_accepted_by_gym_chat_completions(self) -> None:
agent = _make_agent(model="m", model_server=ModelServerRef(type="responses_api_models", name="policy_model"))
with patch.object(agent, "_resolve_model_base_url", return_value="http://model/v1"):
field = agent._build_opencode_config()["provider"]["nemo"]["models"]["m"]["interleaved"]["field"]

# OpenCode replays an assistant turn after a tool call with the interleaved field set.
replayed = {
"role": "assistant",
"content": "",
field: "thinking",
"tool_calls": [{"id": "c1", "type": "function", "function": {"name": "task", "arguments": "{}"}}],
}
body = NeMoGymChatCompletionCreateParamsNonStreaming.model_validate(
{
"model": "m",
"messages": [
{"role": "user", "content": "hi"},
replayed,
{"role": "tool", "tool_call_id": "c1", "content": "done"},
],
}
)
assert body.messages[1]["reasoning_content"] == "thinking"


class TestRolloutObservability:
def test_routes_model_server_without_mutating_config(self, tmp_path: Path) -> None:
Expand Down
Loading