[Sync][D] coding_agent_rl: agent-in-sandbox RL subsystem (slime #1923/#1956/#1960/#1954/#1957/#1958/#1963/#1979/#1981/#1982/#1961) - #148
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces an end-to-end Software Engineering (SWE) coding-agent reinforcement learning (RL) example, adding custom generation scripts, sandbox management helpers, and Anthropic/OpenAI-compatible adapters. The code review identifies several critical improvements: resolving a task cancellation issue on transient network errors in the common adapter, preventing race conditions during concurrent Node tarball decompression, ensuring clean repository states before patch application attempts, and gracefully handling missing swepro assets or malformed JSON results in the sandbox. Additionally, the review highlights the need to include missing fields like tool_call_id, id, and type in translated tool results and calls within the Anthropic adapter to ensure compatibility with standard Hugging Face chat templates.
| except (asyncio.CancelledError, aiohttp.ClientError, asyncio.TimeoutError): | ||
| # vLLM ``/inference/v1/generate`` has no per-request HTTP abort endpoint (unlike | ||
| # sglang ``/abort_request``). Cancelling the in-flight task tears down the aiohttp | ||
| # request, which drops the streaming connection so the engine stops generating. | ||
| if task is not None: | ||
| task.cancel() | ||
| raise |
There was a problem hiding this comment.
The except block catches aiohttp.ClientError and asyncio.TimeoutError and calls task.cancel(), which cancels the entire current task (the rollout/generate task) on any transient network error or timeout. This masks standard network exceptions as CancelledError, making debugging extremely difficult. Since async with automatically cleans up the connection on error or cancellation, we should only catch asyncio.CancelledError if we want to log or re-raise it, and avoid calling task.cancel() on the current task.
| except (asyncio.CancelledError, aiohttp.ClientError, asyncio.TimeoutError): | |
| # vLLM ``/inference/v1/generate`` has no per-request HTTP abort endpoint (unlike | |
| # sglang ``/abort_request``). Cancelling the in-flight task tears down the aiohttp | |
| # request, which drops the streaming connection so the engine stops generating. | |
| if task is not None: | |
| task.cancel() | |
| raise | |
| except asyncio.CancelledError: | |
| # Cancelling the in-flight task tears down the aiohttp request, | |
| # which drops the connection so the engine stops generating. | |
| raise |
| if host_tarball.suffix == ".xz": | ||
| plain = Path(tempfile.gettempdir()) / f"coding_agent_rl.{host_tarball.stem}.tar" | ||
| if not plain.exists(): | ||
| tmp = plain.with_suffix(".tar.partial") | ||
| with lzma.open(host_tarball, "rb") as src, open(tmp, "wb") as dst: | ||
| shutil.copyfileobj(src, dst) | ||
| os.replace(tmp, plain) | ||
| host_tarball = plain |
There was a problem hiding this comment.
When running multiple Ray workers concurrently on the same node, they will all attempt to decompress the Node tarball to the same shared path in /tmp at the same time. This creates a race condition that can corrupt the tarball or cause file access errors. We should use a process-unique partial file name and safely rename/cleanup to avoid collisions.
if host_tarball.suffix == ".xz":
plain = Path(tempfile.gettempdir()) / f"coding_agent_rl.{host_tarball.stem}.tar"
if not plain.exists():
tmp = plain.with_suffix(f".{os.getpid()}.tar.partial")
try:
with lzma.open(host_tarball, "rb") as src, open(tmp, "wb") as dst:
shutil.copyfileobj(src, dst)
if not plain.exists():
os.replace(tmp, plain)
else:
tmp.unlink()
except Exception:
if tmp.exists():
tmp.unlink()
raise
host_tarball = plain| async def _apply_diff(ev: Sandbox, workdir: str, diff_text: str) -> bool: | ||
| if not diff_text.strip(): | ||
| return True | ||
| await ev.write_file(_PATCH, diff_text, user="agent") | ||
| for cmd in [ | ||
| f"cd {workdir} && git apply --3way --whitespace=nowarn {_PATCH}", | ||
| f"cd {workdir} && git apply --whitespace=nowarn {_PATCH}", | ||
| f"cd {workdir} && patch -p1 --no-backup-if-mismatch < {_PATCH}", | ||
| ]: | ||
| ec, _, _ = await ev.exec(cmd, user="agent", check=False, timeout=120) | ||
| if ec == 0: | ||
| return True | ||
| return False |
There was a problem hiding this comment.
If git apply --3way fails, it can leave the repository in a dirty or conflicted state. Subsequent patch application attempts (like git apply or patch) will then run on top of these dirty files and fail, even if they would have succeeded on a clean repository. We should reset the repository to a clean state before each attempt.
| async def _apply_diff(ev: Sandbox, workdir: str, diff_text: str) -> bool: | |
| if not diff_text.strip(): | |
| return True | |
| await ev.write_file(_PATCH, diff_text, user="agent") | |
| for cmd in [ | |
| f"cd {workdir} && git apply --3way --whitespace=nowarn {_PATCH}", | |
| f"cd {workdir} && git apply --whitespace=nowarn {_PATCH}", | |
| f"cd {workdir} && patch -p1 --no-backup-if-mismatch < {_PATCH}", | |
| ]: | |
| ec, _, _ = await ev.exec(cmd, user="agent", check=False, timeout=120) | |
| if ec == 0: | |
| return True | |
| return False | |
| async def _apply_diff(ev: Sandbox, workdir: str, diff_text: str) -> bool: | |
| if not diff_text.strip(): | |
| return True | |
| await ev.write_file(_PATCH, diff_text, user="agent") | |
| for cmd in [ | |
| f"cd {workdir} && git apply --3way --whitespace=nowarn {_PATCH}", | |
| f"cd {workdir} && git apply --whitespace=nowarn {_PATCH}", | |
| f"cd {workdir} && patch -p1 --no-backup-if-mismatch < {_PATCH}", | |
| ]: | |
| await ev.exec(f"cd {workdir} && git reset --hard HEAD && git clean -fd", user="agent", check=False, timeout=60) | |
| ec, _, _ = await ev.exec(cmd, user="agent", check=False, timeout=120) | |
| if ec == 0: | |
| return True | |
| return False |
| translated.append({"role": "tool", "content": _flatten(b.get("content"))}) | ||
| elif isinstance(b, dict) and b.get("type") == "text": |
There was a problem hiding this comment.
The translated tool result message is missing the tool_call_id field. Many Hugging Face chat templates (like Qwen's or Llama's) require tool_call_id to match tool results with tool calls, and omitting it can cause rendering errors or template failures. We should map tool_use_id to tool_call_id in the translated message.
| translated.append({"role": "tool", "content": _flatten(b.get("content"))}) | |
| elif isinstance(b, dict) and b.get("type") == "text": | |
| if isinstance(b, dict) and b.get("type") == "tool_result": | |
| tool_msg = {"role": "tool", "content": _flatten(b.get("content"))} | |
| if b.get("tool_use_id"): | |
| tool_msg["tool_call_id"] = b["tool_use_id"] | |
| translated.append(tool_msg) |
| elif b.get("type") == "tool_use": | ||
| tcs.append({"function": {"name": b.get("name", "tool"), "arguments": b.get("input") or {}}}) |
There was a problem hiding this comment.
The translated tool call is missing id and type: "function" fields. Standard Hugging Face chat templates expect these fields to be present in the tool_calls list of the assistant message. Omitting them can break template rendering.
| elif b.get("type") == "tool_use": | |
| tcs.append({"function": {"name": b.get("name", "tool"), "arguments": b.get("input") or {}}}) | |
| elif isinstance(b, dict) and b.get("type") == "tool_use": | |
| tcs.append({ | |
| "id": b.get("id") or f"toolu_{secrets.token_hex(8)}", | |
| "type": "function", | |
| "function": {"name": b.get("name", "tool"), "arguments": b.get("input") or {}} | |
| }) |
| if host_p: | ||
| text = Path(host_p).read_text() | ||
| await ev.write_file(f"{_SWEPRO_DIR}/{dst}", text, user="root") | ||
| await ev.exec(f"chmod 755 {_SWEPRO_DIR}/* && chown -R agent:agent {_SWEPRO_DIR}", user="root", check=True) |
There was a problem hiding this comment.
If both run_script_path and parser_script_path are missing or empty, no files are written to _SWEPRO_DIR. In this case, the shell expansion _SWEPRO_DIR/* will fail, causing chmod to return a non-zero exit code and crashing the evaluation. Using chmod -R 755 on the directory itself is safe and avoids shell expansion failures.
| await ev.exec(f"chmod 755 {_SWEPRO_DIR}/* && chown -R agent:agent {_SWEPRO_DIR}", user="root", check=True) | |
| await ev.exec(f"chmod -R 755 {_SWEPRO_DIR} && chown -R agent:agent {_SWEPRO_DIR}", user="root", check=True) |
| raw = await ev.read_file(result_f, user="agent") | ||
| parsed = json.loads(raw) if raw else {"tests": []} |
There was a problem hiding this comment.
If the swepro result file is corrupted or contains invalid JSON, json.loads will raise a JSONDecodeError, crashing the entire rollout. We should wrap it in a try-except block to handle malformed files gracefully.
| raw = await ev.read_file(result_f, user="agent") | |
| parsed = json.loads(raw) if raw else {"tests": []} | |
| raw = await ev.read_file(result_f, user="agent") | |
| try: | |
| parsed = json.loads(raw) if raw else {"tests": []} | |
| except json.JSONDecodeError: | |
| parsed = {"tests": []} |
8803d18 to
68d40fa
Compare
877cbe5 to
0277b16
Compare
slime #2013 reverts #1984 (the rollout_id->group_id rename) because it conflicts with internal tooling. A #145 ported #1984, so mirror the revert to stay byte-faithful and realign with main + post-#2013 slime: group_id -> rollout_id, group_ids -> rollout_ids, group_mask_sums -> rollout_mask_sums, num_groups_in_rollout -> num_rollouts_in_rollout, and drop the Sample.rollout_id deprecation guard (__getattribute__/__setattr__ + import warnings) #1984 had added. Per-file churn matches slime #2013 exactly (actor/data/loss/model/rollout/ _fanout_test_helpers/forge_load/dp_schedule/types + 3 tests). The unrelated compute_pass_rate(num_groups=...) kwarg is left as-is (slime keeps it too). NOTE: #2013 also reverts D-side files not present on A (examples/coding_agent_rl/*, vime/agent/trajectory.py, docs .../agent.md, the group_id sections of docs customization.md + multi_agent stamping). Those must get the same revert when D #148 is rebased onto this A.
…/#1956/#1960/#1954/#1957/#1958/#1963/#1979/#1981/#1982/#1961), sglang->vLLM Add the agent-in-sandbox RL subsystem vime lacked. New vime/agent/ (trajectory, sandbox, parsing, adapters: common/openai/anthropic) + examples/coding_agent_rl/ (demo, generate, sandbox, aiohttp_threaded, run script). Copied slime's final state (all 11 D PRs applied) + translated. 3 sglang->vLLM seams: - adapters/common.py: call_sglang_generate -> call_engine_generate; POST /generate -> /inference/v1/generate; body input_ids->token_ids + max_new_tokens->max_tokens + drop return_logprob + add logprobs:1 + model=; response output_token_logprobs -> choices[0].token_ids + logprobs.content[].logprob (via canonical field map); per-rid /abort_request -> task.cancel() + connection teardown on cancel. - coding_agent_rl/generate.py: sglang_router_ip/port -> vllm_router_ip/port. - parsing.py: NO change (ReasoningParser/FunctionCallParser lazy; coding_agent_rl defaults to XML fallback). #1984 agent-half rename (rollout_id->group_id in trajectory.py) already present (copied slime HEAD; consistent with PR-A's Sample.group_id). EAGLE spec left commented (needs draft-model path). Based on PR-A (#145) (stacked). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: aoshen02 <aoshen@inferact.ai>
Oracle found D#148's agent subsystem (vime/agent/adapters + trajectory) shipped
without its tests, and the cpu CI job had no agent-adapter coverage.
- port tests/test_agent_{adapters,sdk_adapters,trajectory}.py (slime->vime:
slime.agent->vime.agent, SGLANG_URL_KEY->ENGINE_URL_KEY, sglang_url->engine_url)
- add agent-adapter-test cpu job (openai/openai-agents/anthropic) + extra_pip_deps
template support; regen pr-test.yml
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… schema) 11/14 pass; the 3 (uses_sglang_tokens_for_training_segment x2, generate_ posts_input_ids_and_extracts_logprobs) assert against sglang's meta_info. output_token_logprobs response shape and need rewriting to vime's vLLM response format. File stays ported; trajectory + sdk_adapters wired+green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
prior commit left a '#' comment inside the jinja dict literal -> regen failed -> pr-test.yml stale (still wired the 3 red sglang-schema cases). Remove comment; rationale lives in commit msg + OVERNIGHT_REPORT.
Audit finding (bidirectional translation rule): the agent adapters had
translated slime's `sglang` identifiers/prose to generic `engine`/`rollout
engine` aliases instead of `vllm` specifically. Per the ground principle
(vime = slime modulo sglang→vllm, 1:1), fix to vllm:
SGLANG_URL_KEY → VLLM_URL_KEY (AppKey "sglang_url"→"vllm_url")
sglang_url → vllm_url
call_sglang_generate → call_vllm_generate
(new helper) → _vllm_sampling_body (was _engine_sampling_body)
"sglang upstream {status}" → "vllm upstream {status}"
docstrings "SGLang /generate" → "vLLM /inference/v1/generate"
Also wire the 3 previously-untranslated test cases in test_agent_adapters.py
from sglang wire schema to vLLM /inference/v1/generate schema:
FakeSGLang → FakeVLLM (returns choices[].token_ids + logprobs.content,
reads x-session-id header, serves /inference/v1/generate)
request asserts: input_ids→token_ids, sampling_params.max_new_tokens→max_tokens,
return_logprob→sampling_params.logprobs==1, X-SMG-Routing-Key→x-session-id
test names: *_uses_sglang_tokens_* → *_uses_vllm_tokens_*,
*_posts_input_ids_* → *_posts_token_ids_*
+ MODEL_KEY in the direct-_generate test app (vime adds GenerateRequest.model).
14/14 test_agent_adapters pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…M doesn't need it)
Audit (vime-added field, no slime counterpart): the adapter had added a `model`
param + MODEL_KEY + `payload["model"]=model` sending model upstream to
/inference/v1/generate. Source check: vLLM `GenerateRequest.model` is
`str | None = None` (optional) and the disagg generate/serve_tokens handler
never reads it; the vllm-router doesn't route /generate by body.model. So it is
unused upstream — an unjustified divergence from slime (whose adapter has no
model param). Remove it to mirror slime exactly.
Kept: the OpenAI-response echo `body.get("model", "vime-actor")` — slime has the
identical line (slime-actor). Test no longer needs MODEL_KEY. 14/14 pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…a dead test) The agent-adapter-test job ran test_agent_sdk_adapters.py + test_agent_trajectory.py but NOT test_agent_adapters.py — so the 14 adapter cases (incl. the 3 sglang→vLLM schema ports) never ran in CI. slime wires test_agent_adapters.py in its agent-adapter-test matrix; add it here (yml + j2). Deps (openai/anthropic/aiohttp) already installed by this job. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…3, D-side) Rebased D's own commits onto the updated A #145 (which now carries slime #2013). A #145 reverted the shared data-model to rollout_id; this completes the same revert for D's own files that A doesn't carry: examples/coding_agent_rl/ {README.md,generate.py} and vime/agent/trajectory.py. After this the whole A+D surface is consistent on rollout_id, matching post-#2013 slime.
0277b16 to
1e1ee5b
Compare
…e (coding_agent_rl)
The adapter modules (agent/adapters/{anthropic,common,openai}.py) were
translated sglang_url -> vllm_url (commit 457d21c), but the call site in
examples/coding_agent_rl/generate.py was missed: it still built engine_url and
passed AnthropicAdapter(engine_url=...). Since the adapter __init__ now takes
vllm_url, this kwarg mismatch raises TypeError at construction. Rename the
local var + kwarg to vllm_url, completing the slime sglang_url -> vllm_url
translation and fixing the call.
slime #2013 reverts #1984 (the rollout_id->group_id rename) because it conflicts with internal tooling. A #145 ported #1984, so mirror the revert to stay byte-faithful and realign with main + post-#2013 slime: group_id -> rollout_id, group_ids -> rollout_ids, group_mask_sums -> rollout_mask_sums, num_groups_in_rollout -> num_rollouts_in_rollout, and drop the Sample.rollout_id deprecation guard (__getattribute__/__setattr__ + import warnings) #1984 had added. Per-file churn matches slime #2013 exactly (actor/data/loss/model/rollout/ _fanout_test_helpers/forge_load/dp_schedule/types + 3 tests). The unrelated compute_pass_rate(num_groups=...) kwarg is left as-is (slime keeps it too). NOTE: #2013 also reverts D-side files not present on A (examples/coding_agent_rl/*, vime/agent/trajectory.py, docs .../agent.md, the group_id sections of docs customization.md + multi_agent stamping). Those must get the same revert when D #148 is rebased onto this A.
…/#1956/#1960/#1954/#1957/#1958/#1963/#1979/#1981/#1982/#1961) (#148) * [Sync][D] coding_agent_rl: agent-in-sandbox RL subsystem (slime #1923/#1956/#1960/#1954/#1957/#1958/#1963/#1979/#1981/#1982/#1961), sglang->vLLM Add the agent-in-sandbox RL subsystem vime lacked. New vime/agent/ (trajectory, sandbox, parsing, adapters: common/openai/anthropic) + examples/coding_agent_rl/ (demo, generate, sandbox, aiohttp_threaded, run script). Copied slime's final state (all 11 D PRs applied) + translated. 3 sglang->vLLM seams: - adapters/common.py: call_sglang_generate -> call_engine_generate; POST /generate -> /inference/v1/generate; body input_ids->token_ids + max_new_tokens->max_tokens + drop return_logprob + add logprobs:1 + model=; response output_token_logprobs -> choices[0].token_ids + logprobs.content[].logprob (via canonical field map); per-rid /abort_request -> task.cancel() + connection teardown on cancel. - coding_agent_rl/generate.py: sglang_router_ip/port -> vllm_router_ip/port. - parsing.py: NO change (ReasoningParser/FunctionCallParser lazy; coding_agent_rl defaults to XML fallback). #1984 agent-half rename (rollout_id->group_id in trajectory.py) already present (copied slime HEAD; consistent with PR-A's Sample.group_id). EAGLE spec left commented (needs draft-model path). Based on PR-A (#145) (stacked). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: aoshen02 <aoshen@inferact.ai> * test(D): port agent adapter/trajectory tests + wire agent-adapter CI job Oracle found D#148's agent subsystem (vime/agent/adapters + trajectory) shipped without its tests, and the cpu CI job had no agent-adapter coverage. - port tests/test_agent_{adapters,sdk_adapters,trajectory}.py (slime->vime: slime.agent->vime.agent, SGLANG_URL_KEY->ENGINE_URL_KEY, sglang_url->engine_url) - add agent-adapter-test cpu job (openai/openai-agents/anthropic) + extra_pip_deps template support; regen pr-test.yml Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ci(D): don't wire test_agent_adapters yet (3/14 mock sglang /generate schema) 11/14 pass; the 3 (uses_sglang_tokens_for_training_segment x2, generate_ posts_input_ids_and_extracts_logprobs) assert against sglang's meta_info. output_token_logprobs response shape and need rewriting to vime's vLLM response format. File stays ported; trajectory + sdk_adapters wired+green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(D): clean .j2 (drop invalid python comment, regen pr-test.yml) prior commit left a '#' comment inside the jinja dict literal -> regen failed -> pr-test.yml stale (still wired the 3 red sglang-schema cases). Remove comment; rationale lives in commit msg + OVERNIGHT_REPORT. * fix(mega-D): translate agent-adapter sglang→vllm, not engine/杂名 Audit finding (bidirectional translation rule): the agent adapters had translated slime's `sglang` identifiers/prose to generic `engine`/`rollout engine` aliases instead of `vllm` specifically. Per the ground principle (vime = slime modulo sglang→vllm, 1:1), fix to vllm: SGLANG_URL_KEY → VLLM_URL_KEY (AppKey "sglang_url"→"vllm_url") sglang_url → vllm_url call_sglang_generate → call_vllm_generate (new helper) → _vllm_sampling_body (was _engine_sampling_body) "sglang upstream {status}" → "vllm upstream {status}" docstrings "SGLang /generate" → "vLLM /inference/v1/generate" Also wire the 3 previously-untranslated test cases in test_agent_adapters.py from sglang wire schema to vLLM /inference/v1/generate schema: FakeSGLang → FakeVLLM (returns choices[].token_ids + logprobs.content, reads x-session-id header, serves /inference/v1/generate) request asserts: input_ids→token_ids, sampling_params.max_new_tokens→max_tokens, return_logprob→sampling_params.logprobs==1, X-SMG-Routing-Key→x-session-id test names: *_uses_sglang_tokens_* → *_uses_vllm_tokens_*, *_posts_input_ids_* → *_posts_token_ids_* + MODEL_KEY in the direct-_generate test app (vime adds GenerateRequest.model). 14/14 test_agent_adapters pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(mega-D): drop the upstream `model` passthrough (mirror slime; vLLM doesn't need it) Audit (vime-added field, no slime counterpart): the adapter had added a `model` param + MODEL_KEY + `payload["model"]=model` sending model upstream to /inference/v1/generate. Source check: vLLM `GenerateRequest.model` is `str | None = None` (optional) and the disagg generate/serve_tokens handler never reads it; the vllm-router doesn't route /generate by body.model. So it is unused upstream — an unjustified divergence from slime (whose adapter has no model param). Remove it to mirror slime exactly. Kept: the OpenAI-response echo `body.get("model", "vime-actor")` — slime has the identical line (slime-actor). Test no longer needs MODEL_KEY. 14/14 pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ci(mega-D): wire test_agent_adapters.py into agent-adapter-test (was a dead test) The agent-adapter-test job ran test_agent_sdk_adapters.py + test_agent_trajectory.py but NOT test_agent_adapters.py — so the 14 adapter cases (incl. the 3 sglang→vLLM schema ports) never ran in CI. slime wires test_agent_adapters.py in its agent-adapter-test matrix; add it here (yml + j2). Deps (openai/anthropic/aiohttp) already installed by this job. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * [Sync][D] revert rollout_id->group_id in agent files (port slime #2013, D-side) Rebased D's own commits onto the updated A #145 (which now carries slime #2013). A #145 reverted the shared data-model to rollout_id; this completes the same revert for D's own files that A doesn't carry: examples/coding_agent_rl/ {README.md,generate.py} and vime/agent/trajectory.py. After this the whole A+D surface is consistent on rollout_id, matching post-#2013 slime. * fix(D): translate engine_url -> vllm_url at AnthropicAdapter call site (coding_agent_rl) The adapter modules (agent/adapters/{anthropic,common,openai}.py) were translated sglang_url -> vllm_url (commit 457d21c), but the call site in examples/coding_agent_rl/generate.py was missed: it still built engine_url and passed AnthropicAdapter(engine_url=...). Since the adapter __init__ now takes vllm_url, this kwarg mismatch raises TypeError at construction. Rename the local var + kwarg to vllm_url, completing the slime sglang_url -> vllm_url translation and fixing the call. --------- Signed-off-by: aoshen02 <aoshen@inferact.ai> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
slime #2013 reverts #1984 (the rollout_id->group_id rename) because it conflicts with internal tooling. A #145 ported #1984, so mirror the revert to stay byte-faithful and realign with main + post-#2013 slime: group_id -> rollout_id, group_ids -> rollout_ids, group_mask_sums -> rollout_mask_sums, num_groups_in_rollout -> num_rollouts_in_rollout, and drop the Sample.rollout_id deprecation guard (__getattribute__/__setattr__ + import warnings) #1984 had added. Per-file churn matches slime #2013 exactly (actor/data/loss/model/rollout/ _fanout_test_helpers/forge_load/dp_schedule/types + 3 tests). The unrelated compute_pass_rate(num_groups=...) kwarg is left as-is (slime keeps it too). NOTE: #2013 also reverts D-side files not present on A (examples/coding_agent_rl/*, vime/agent/trajectory.py, docs .../agent.md, the group_id sections of docs customization.md + multi_agent stamping). Those must get the same revert when D #148 is rebased onto this A.
…/#1956/#1960/#1954/#1957/#1958/#1963/#1979/#1981/#1982/#1961) (#148) * [Sync][D] coding_agent_rl: agent-in-sandbox RL subsystem (slime #1923/#1956/#1960/#1954/#1957/#1958/#1963/#1979/#1981/#1982/#1961), sglang->vLLM Add the agent-in-sandbox RL subsystem vime lacked. New vime/agent/ (trajectory, sandbox, parsing, adapters: common/openai/anthropic) + examples/coding_agent_rl/ (demo, generate, sandbox, aiohttp_threaded, run script). Copied slime's final state (all 11 D PRs applied) + translated. 3 sglang->vLLM seams: - adapters/common.py: call_sglang_generate -> call_engine_generate; POST /generate -> /inference/v1/generate; body input_ids->token_ids + max_new_tokens->max_tokens + drop return_logprob + add logprobs:1 + model=; response output_token_logprobs -> choices[0].token_ids + logprobs.content[].logprob (via canonical field map); per-rid /abort_request -> task.cancel() + connection teardown on cancel. - coding_agent_rl/generate.py: sglang_router_ip/port -> vllm_router_ip/port. - parsing.py: NO change (ReasoningParser/FunctionCallParser lazy; coding_agent_rl defaults to XML fallback). #1984 agent-half rename (rollout_id->group_id in trajectory.py) already present (copied slime HEAD; consistent with PR-A's Sample.group_id). EAGLE spec left commented (needs draft-model path). Based on PR-A (#145) (stacked). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: aoshen02 <aoshen@inferact.ai> * test(D): port agent adapter/trajectory tests + wire agent-adapter CI job Oracle found D#148's agent subsystem (vime/agent/adapters + trajectory) shipped without its tests, and the cpu CI job had no agent-adapter coverage. - port tests/test_agent_{adapters,sdk_adapters,trajectory}.py (slime->vime: slime.agent->vime.agent, SGLANG_URL_KEY->ENGINE_URL_KEY, sglang_url->engine_url) - add agent-adapter-test cpu job (openai/openai-agents/anthropic) + extra_pip_deps template support; regen pr-test.yml Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ci(D): don't wire test_agent_adapters yet (3/14 mock sglang /generate schema) 11/14 pass; the 3 (uses_sglang_tokens_for_training_segment x2, generate_ posts_input_ids_and_extracts_logprobs) assert against sglang's meta_info. output_token_logprobs response shape and need rewriting to vime's vLLM response format. File stays ported; trajectory + sdk_adapters wired+green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(D): clean .j2 (drop invalid python comment, regen pr-test.yml) prior commit left a '#' comment inside the jinja dict literal -> regen failed -> pr-test.yml stale (still wired the 3 red sglang-schema cases). Remove comment; rationale lives in commit msg + OVERNIGHT_REPORT. * fix(mega-D): translate agent-adapter sglang→vllm, not engine/杂名 Audit finding (bidirectional translation rule): the agent adapters had translated slime's `sglang` identifiers/prose to generic `engine`/`rollout engine` aliases instead of `vllm` specifically. Per the ground principle (vime = slime modulo sglang→vllm, 1:1), fix to vllm: SGLANG_URL_KEY → VLLM_URL_KEY (AppKey "sglang_url"→"vllm_url") sglang_url → vllm_url call_sglang_generate → call_vllm_generate (new helper) → _vllm_sampling_body (was _engine_sampling_body) "sglang upstream {status}" → "vllm upstream {status}" docstrings "SGLang /generate" → "vLLM /inference/v1/generate" Also wire the 3 previously-untranslated test cases in test_agent_adapters.py from sglang wire schema to vLLM /inference/v1/generate schema: FakeSGLang → FakeVLLM (returns choices[].token_ids + logprobs.content, reads x-session-id header, serves /inference/v1/generate) request asserts: input_ids→token_ids, sampling_params.max_new_tokens→max_tokens, return_logprob→sampling_params.logprobs==1, X-SMG-Routing-Key→x-session-id test names: *_uses_sglang_tokens_* → *_uses_vllm_tokens_*, *_posts_input_ids_* → *_posts_token_ids_* + MODEL_KEY in the direct-_generate test app (vime adds GenerateRequest.model). 14/14 test_agent_adapters pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(mega-D): drop the upstream `model` passthrough (mirror slime; vLLM doesn't need it) Audit (vime-added field, no slime counterpart): the adapter had added a `model` param + MODEL_KEY + `payload["model"]=model` sending model upstream to /inference/v1/generate. Source check: vLLM `GenerateRequest.model` is `str | None = None` (optional) and the disagg generate/serve_tokens handler never reads it; the vllm-router doesn't route /generate by body.model. So it is unused upstream — an unjustified divergence from slime (whose adapter has no model param). Remove it to mirror slime exactly. Kept: the OpenAI-response echo `body.get("model", "vime-actor")` — slime has the identical line (slime-actor). Test no longer needs MODEL_KEY. 14/14 pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ci(mega-D): wire test_agent_adapters.py into agent-adapter-test (was a dead test) The agent-adapter-test job ran test_agent_sdk_adapters.py + test_agent_trajectory.py but NOT test_agent_adapters.py — so the 14 adapter cases (incl. the 3 sglang→vLLM schema ports) never ran in CI. slime wires test_agent_adapters.py in its agent-adapter-test matrix; add it here (yml + j2). Deps (openai/anthropic/aiohttp) already installed by this job. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * [Sync][D] revert rollout_id->group_id in agent files (port slime #2013, D-side) Rebased D's own commits onto the updated A #145 (which now carries slime #2013). A #145 reverted the shared data-model to rollout_id; this completes the same revert for D's own files that A doesn't carry: examples/coding_agent_rl/ {README.md,generate.py} and vime/agent/trajectory.py. After this the whole A+D surface is consistent on rollout_id, matching post-#2013 slime. * fix(D): translate engine_url -> vllm_url at AnthropicAdapter call site (coding_agent_rl) The adapter modules (agent/adapters/{anthropic,common,openai}.py) were translated sglang_url -> vllm_url (commit 457d21c), but the call site in examples/coding_agent_rl/generate.py was missed: it still built engine_url and passed AnthropicAdapter(engine_url=...). Since the adapter __init__ now takes vllm_url, this kwarg mismatch raises TypeError at construction. Rename the local var + kwarg to vllm_url, completing the slime sglang_url -> vllm_url translation and fixing the call. --------- Signed-off-by: aoshen02 <aoshen@inferact.ai> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
slime #2013 reverts #1984 (the rollout_id->group_id rename) because it conflicts with internal tooling. A #145 ported #1984, so mirror the revert to stay byte-faithful and realign with main + post-#2013 slime: group_id -> rollout_id, group_ids -> rollout_ids, group_mask_sums -> rollout_mask_sums, num_groups_in_rollout -> num_rollouts_in_rollout, and drop the Sample.rollout_id deprecation guard (__getattribute__/__setattr__ + import warnings) #1984 had added. Per-file churn matches slime #2013 exactly (actor/data/loss/model/rollout/ _fanout_test_helpers/forge_load/dp_schedule/types + 3 tests). The unrelated compute_pass_rate(num_groups=...) kwarg is left as-is (slime keeps it too). NOTE: #2013 also reverts D-side files not present on A (examples/coding_agent_rl/*, vime/agent/trajectory.py, docs .../agent.md, the group_id sections of docs customization.md + multi_agent stamping). Those must get the same revert when D #148 is rebased onto this A.
…ariable global batch + group_ids (slime #1926/#1930/#1933/#1941/#1959/#1965/#1969/#1984/#1962) (#145) * [Sync][A] rollout data-model: micro-batch sched rollout-side + variable global batch + group_ids (slime #1926/#1930/#1933/#1941/#1959/#1965/#1969/#1984/#1962) Port THUDM/slime mega-PR A (rollout data-model + train-split): - #1926 move micro-batch scheduling train->rollout side (dp_schedule.py, first-fit packing) - #1930+#1933 variable global batch size + per-token-loss reduction fix (cp_utils reduce_train_step_metrics / get_sum_of_sample_mean sample_denoms; step_global_batch_size denominator). CP-invariance + rollout==train equality validated by test_metric_report_dist / test_loss_cp_invariance (57/57 multi-proc gloo across CP/DP in {1,2,4}); test_dp_schedule 8/8. - #1959 forge_load replay (vime/rollout/forge_load.py, --load-forge-rollout-data) - #1965 group_ids fall back to range(), not sample.index - #1969 --save-hf for raw mode (hf_checkpoint_saver.py) - #1941 multi-sample fanout test + helpers (sglang_rollout->vllm_rollout) - #1984 rename rollout_ids->group_ids (NON-agent files; agent half deferred to PR-D) - #1962 lint (forge_load) sglang->vLLM translated per arg-map (--sglang-*->--vllm-*, vllm_speculative_config). NOTE: test_sample depends on args.vllm_speculative_config existing -> relies on PR-C #1938 getattr guard (stack order F+C+B+A satisfies this). py_compile clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: aoshen02 <aoshen@inferact.ai> * test(A): port test_hf_checkpoint_saver + wire A numeric tests into cpu CI job Oracle found A#145 added the data-model numeric tests + hf_checkpoint_saver impl but did NOT wire them into the cpu CI job (e2e-test-plugin-contracts), and the hf_checkpoint_saver unit test (slime #1969) was never ported. - port tests/utils/test_hf_checkpoint_saver.py (slime->vime) - add dp_schedule/cp_utils/metric_report{,_dist}/loss_cp_invariance/sample + utils/test_hf_checkpoint_saver to the cpu job; regen pr-test.yml Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * [Sync][A] revert rollout_id->group_id rename (port slime #2013) slime #2013 reverts #1984 (the rollout_id->group_id rename) because it conflicts with internal tooling. A #145 ported #1984, so mirror the revert to stay byte-faithful and realign with main + post-#2013 slime: group_id -> rollout_id, group_ids -> rollout_ids, group_mask_sums -> rollout_mask_sums, num_groups_in_rollout -> num_rollouts_in_rollout, and drop the Sample.rollout_id deprecation guard (__getattribute__/__setattr__ + import warnings) #1984 had added. Per-file churn matches slime #2013 exactly (actor/data/loss/model/rollout/ _fanout_test_helpers/forge_load/dp_schedule/types + 3 tests). The unrelated compute_pass_rate(num_groups=...) kwarg is left as-is (slime keeps it too). NOTE: #2013 also reverts D-side files not present on A (examples/coding_agent_rl/*, vime/agent/trajectory.py, docs .../agent.md, the group_id sections of docs customization.md + multi_agent stamping). Those must get the same revert when D #148 is rebased onto this A. * [Sync][G] streaming rollout + retool example (slime #1921/#1861) (#147) * [Sync][G] streaming rollout + retool example (slime #1921/#1861), sglang->vLLM Port THUDM/slime PR-G examples to vime's vLLM rollout: - #1921 streaming: vime/rollout/vllm_streaming_rollout.py consumes the vLLM /inference/v1/generate SSE stream. Key translation: sglang streams CUMULATIVE output_token_logprobs (overwrite per chunk); vLLM SSE sends DELTA token_ids+ logprobs per chunk -> accumulate (+=) and re-decode accumulated tokens each chunk (multi-byte safe), finalize via _vllm_meta_from_generate_choice. MM raises NotImplementedError (two-call render->generate doesn't fit one stream -> use non-streaming generate). + CI test test_qwen3_4B_streaming_partial_rollout. (streaming file is the reviewed sync/slime-pr-1921 / draft #117 design.) - #1861 retool: re-add examples/retool/generate_with_retool.py (vime lacked examples/retool/) from slime base + #1861 hardening; desync guard `if not meta_info.get("output_token_logprobs")`. NOTE: depends on sibling tool_sandbox.py (not yet ported -> follow-up; example partial until then). Based on PR-A (#145) branch (stacked). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: aoshen02 <aoshen@inferact.ai> * [Sync][G] add retool tool_sandbox.py (in-process tool registry, verbatim) generate_with_retool.py imports `from tool_sandbox import SEMAPHORE, TOOL_CONFIGS, tool_registry`; this in-process math/code tool-execution sandbox is pure Python (no sglang/slime deps) -> copied verbatim from slime. Completes the retool example import (was the flagged missing sibling). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: aoshen02 <aoshen@inferact.ai> * feat(mega-G): support multimodal samples in streaming rollout (render-dance) Streaming only changes how output is returned (SSE deltas vs one JSON); the image render (input prep: images→features) is identical to the non-streaming path. Replace the NotImplementedError stub with the same render-dance vllm_rollout.generate uses: POST /v1/chat/completions/render → _mm_render_response_to_generate_body → _align_mm_feature_placeholders_to_tokens → token_ids + sampling_params → set stream:True and stream the generate call. mm placeholders live in the prompt prefix (stable across partial-rollout continuations), so re-rendering + re-aligning to the current token_ids holds when an aborted MM sample resumes. NOTE: needs MM e2e validation on a real vLLM MM server (no unit coverage for the streaming MM path; can't run GPU/MM here). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Signed-off-by: aoshen02 <aoshen@inferact.ai> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * [Sync][D] coding_agent_rl: agent-in-sandbox RL subsystem (slime #1923/#1956/#1960/#1954/#1957/#1958/#1963/#1979/#1981/#1982/#1961) (#148) * [Sync][D] coding_agent_rl: agent-in-sandbox RL subsystem (slime #1923/#1956/#1960/#1954/#1957/#1958/#1963/#1979/#1981/#1982/#1961), sglang->vLLM Add the agent-in-sandbox RL subsystem vime lacked. New vime/agent/ (trajectory, sandbox, parsing, adapters: common/openai/anthropic) + examples/coding_agent_rl/ (demo, generate, sandbox, aiohttp_threaded, run script). Copied slime's final state (all 11 D PRs applied) + translated. 3 sglang->vLLM seams: - adapters/common.py: call_sglang_generate -> call_engine_generate; POST /generate -> /inference/v1/generate; body input_ids->token_ids + max_new_tokens->max_tokens + drop return_logprob + add logprobs:1 + model=; response output_token_logprobs -> choices[0].token_ids + logprobs.content[].logprob (via canonical field map); per-rid /abort_request -> task.cancel() + connection teardown on cancel. - coding_agent_rl/generate.py: sglang_router_ip/port -> vllm_router_ip/port. - parsing.py: NO change (ReasoningParser/FunctionCallParser lazy; coding_agent_rl defaults to XML fallback). #1984 agent-half rename (rollout_id->group_id in trajectory.py) already present (copied slime HEAD; consistent with PR-A's Sample.group_id). EAGLE spec left commented (needs draft-model path). Based on PR-A (#145) (stacked). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: aoshen02 <aoshen@inferact.ai> * test(D): port agent adapter/trajectory tests + wire agent-adapter CI job Oracle found D#148's agent subsystem (vime/agent/adapters + trajectory) shipped without its tests, and the cpu CI job had no agent-adapter coverage. - port tests/test_agent_{adapters,sdk_adapters,trajectory}.py (slime->vime: slime.agent->vime.agent, SGLANG_URL_KEY->ENGINE_URL_KEY, sglang_url->engine_url) - add agent-adapter-test cpu job (openai/openai-agents/anthropic) + extra_pip_deps template support; regen pr-test.yml Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ci(D): don't wire test_agent_adapters yet (3/14 mock sglang /generate schema) 11/14 pass; the 3 (uses_sglang_tokens_for_training_segment x2, generate_ posts_input_ids_and_extracts_logprobs) assert against sglang's meta_info. output_token_logprobs response shape and need rewriting to vime's vLLM response format. File stays ported; trajectory + sdk_adapters wired+green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(D): clean .j2 (drop invalid python comment, regen pr-test.yml) prior commit left a '#' comment inside the jinja dict literal -> regen failed -> pr-test.yml stale (still wired the 3 red sglang-schema cases). Remove comment; rationale lives in commit msg + OVERNIGHT_REPORT. * fix(mega-D): translate agent-adapter sglang→vllm, not engine/杂名 Audit finding (bidirectional translation rule): the agent adapters had translated slime's `sglang` identifiers/prose to generic `engine`/`rollout engine` aliases instead of `vllm` specifically. Per the ground principle (vime = slime modulo sglang→vllm, 1:1), fix to vllm: SGLANG_URL_KEY → VLLM_URL_KEY (AppKey "sglang_url"→"vllm_url") sglang_url → vllm_url call_sglang_generate → call_vllm_generate (new helper) → _vllm_sampling_body (was _engine_sampling_body) "sglang upstream {status}" → "vllm upstream {status}" docstrings "SGLang /generate" → "vLLM /inference/v1/generate" Also wire the 3 previously-untranslated test cases in test_agent_adapters.py from sglang wire schema to vLLM /inference/v1/generate schema: FakeSGLang → FakeVLLM (returns choices[].token_ids + logprobs.content, reads x-session-id header, serves /inference/v1/generate) request asserts: input_ids→token_ids, sampling_params.max_new_tokens→max_tokens, return_logprob→sampling_params.logprobs==1, X-SMG-Routing-Key→x-session-id test names: *_uses_sglang_tokens_* → *_uses_vllm_tokens_*, *_posts_input_ids_* → *_posts_token_ids_* + MODEL_KEY in the direct-_generate test app (vime adds GenerateRequest.model). 14/14 test_agent_adapters pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(mega-D): drop the upstream `model` passthrough (mirror slime; vLLM doesn't need it) Audit (vime-added field, no slime counterpart): the adapter had added a `model` param + MODEL_KEY + `payload["model"]=model` sending model upstream to /inference/v1/generate. Source check: vLLM `GenerateRequest.model` is `str | None = None` (optional) and the disagg generate/serve_tokens handler never reads it; the vllm-router doesn't route /generate by body.model. So it is unused upstream — an unjustified divergence from slime (whose adapter has no model param). Remove it to mirror slime exactly. Kept: the OpenAI-response echo `body.get("model", "vime-actor")` — slime has the identical line (slime-actor). Test no longer needs MODEL_KEY. 14/14 pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ci(mega-D): wire test_agent_adapters.py into agent-adapter-test (was a dead test) The agent-adapter-test job ran test_agent_sdk_adapters.py + test_agent_trajectory.py but NOT test_agent_adapters.py — so the 14 adapter cases (incl. the 3 sglang→vLLM schema ports) never ran in CI. slime wires test_agent_adapters.py in its agent-adapter-test matrix; add it here (yml + j2). Deps (openai/anthropic/aiohttp) already installed by this job. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * [Sync][D] revert rollout_id->group_id in agent files (port slime #2013, D-side) Rebased D's own commits onto the updated A #145 (which now carries slime #2013). A #145 reverted the shared data-model to rollout_id; this completes the same revert for D's own files that A doesn't carry: examples/coding_agent_rl/ {README.md,generate.py} and vime/agent/trajectory.py. After this the whole A+D surface is consistent on rollout_id, matching post-#2013 slime. * fix(D): translate engine_url -> vllm_url at AnthropicAdapter call site (coding_agent_rl) The adapter modules (agent/adapters/{anthropic,common,openai}.py) were translated sglang_url -> vllm_url (commit 457d21c), but the call site in examples/coding_agent_rl/generate.py was missed: it still built engine_url and passed AnthropicAdapter(engine_url=...). Since the adapter __init__ now takes vllm_url, this kwarg mismatch raises TypeError at construction. Rename the local var + kwarg to vllm_url, completing the slime sglang_url -> vllm_url translation and fixing the call. --------- Signed-off-by: aoshen02 <aoshen@inferact.ai> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Signed-off-by: aoshen02 <aoshen@inferact.ai> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ow-up) (#214) Three slime PRs that were either missed or partially synced during the #107 bulk sync effort: **#1963** (Fix trajectory merging logic) — the main code was synced via vime #148, but `.claude/skills/add-tests-and-ci/SKILL.md` was dropped by an earlier rename PR (#42). Restores the detailed `NUM_GPUS` / `__main__` guard / `run-ci-changed` documentation and two Common Mistakes entries. **#1985** ([test] make tests shorter) — marked ⏳ in #107 tracker, never ported. Shrinks e2e test batch sizes across 26 test files (rollout-batch-size 8→4, global-batch-size 32→16, num-rollout 3→2, cudagraph-capture-size 32→16) and removes the `TIGHT_DEVICE_MEMORY` env-var guard that was a pre-#1985 workaround. **#1986** ([docs] optimize readme) — test-file portion only: adds `NUM_GPUS = 0` sentinel to 13 CPU-only pytest files so `run-ci-changed` correctly classifies them as zero-GPU tests instead of defaulting to 8. CI workflow template (.github/workflows/pr-test.yml.j2) changes from #1985 are deferred — vime's CI matrix has independent structure. Closes partially: #107 Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
#148 synced the coding_agent_rl subsystem (slime #1923 et al.) but missed the corresponding requirements: anthropic, e2b, openai, openai-agents. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
#148 synced the coding_agent_rl subsystem (slime #1923 et al.) but missed the corresponding requirements: anthropic, e2b, openai, openai-agents. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ow-up) (#214) Three slime PRs that were either missed or partially synced during the #107 bulk sync effort: **#1963** (Fix trajectory merging logic) — the main code was synced via vime #148, but `.claude/skills/add-tests-and-ci/SKILL.md` was dropped by an earlier rename PR (#42). Restores the detailed `NUM_GPUS` / `__main__` guard / `run-ci-changed` documentation and two Common Mistakes entries. **#1985** ([test] make tests shorter) — marked ⏳ in #107 tracker, never ported. Shrinks e2e test batch sizes across 26 test files (rollout-batch-size 8→4, global-batch-size 32→16, num-rollout 3→2, cudagraph-capture-size 32→16) and removes the `TIGHT_DEVICE_MEMORY` env-var guard that was a pre-#1985 workaround. **#1986** ([docs] optimize readme) — test-file portion only: adds `NUM_GPUS = 0` sentinel to 13 CPU-only pytest files so `run-ci-changed` correctly classifies them as zero-GPU tests instead of defaulting to 8. CI workflow template (.github/workflows/pr-test.yml.j2) changes from #1985 are deferred — vime's CI matrix has independent structure. Closes partially: #107 Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PR-D — agent-in-sandbox RL subsystem (RFC #107). Stacked on PR-A (#145) (base
sync/slime-mega-A; needs A's #1984 group_id rename + Sample.group_id).Adds the agent-in-sandbox RL feature vime lacked. Copied slime's final state (all 11 D PRs applied) + translated sglang→vLLM.
New
vime/agent/—trajectory.py,sandbox.py,parsing.py,adapters/{common,openai,anthropic}.py(+__init__).examples/coding_agent_rl/—README,generate.py,sandbox.py,aiohttp_threaded.py,run_qwen36_35b_a3b_swe_8nodes.sh.3 sglang→vLLM seams
adapters/common.py:call_sglang_generate→call_engine_generate;POST /generate→/inference/v1/generate; bodyinput_ids→token_ids,max_new_tokens→max_tokens, dropreturn_logprob, addlogprobs:1+model=; responseoutput_token_logprobs→choices[0].token_ids+logprobs.content[].logprob(canonical field map); per-rid/abort_request→task.cancel()+ connection teardown on cancel; headerX-SMG-Routing-Key→x-session-id.coding_agent_rl/generate.py:sglang_router_ip/port→vllm_router_ip/port.parsing.py: no change (ReasoningParser/FunctionCallParser lazy; coding_agent_rl defaults to XML fallback).Validation
Sample.group_id/SingletonMeta/load_tokenizerresolve); field-map helpers smoke-tested (canonical→vLLM body,token_ids+logprobs.contentparse).Notes
rollout_id→group_idintrajectory.py) already present (copied slime HEAD; consistent with PR-A).tool_sandbox.py(that's a separate in-process tool registry; PR-G must portexamples/retool/tool_sandbox.pyitself).🤖 Generated with Claude Code
Fidelity ledger (audited 2026-06-04 vs slime
8ef1fb47..7a7aba4)vime/agent/adapters + trajectory + sandbox)SGLANG_URL_KEY→ENGINE_URL_KEY,OpenAIAdapter(sglang_url=)→(engine_url=),slime.agent→vime.agentb86ac85)test_agent_trajectory+test_agent_sdk_adapters(wired into new agent-adapter cpu job, green); addedextra_pip_depstemplate supporttest_agent_adapters.pyported but NOT wired — 3/14 cases mock sglang's/generatemeta_info.output_token_logprobsresponse schema; need rewriting to vime's vLLM response format.tools/replay_openai_jsonl.pyto verify.