Skip to content

[Sync][A] rollout data-model: micro-batch scheduling rollout-side + variable global batch + group_ids (slime #1926/#1930/#1933/#1941/#1959/#1965/#1969/#1984/#1962) - #145

Merged
CalvinXKY merged 5 commits into
mainfrom
sync/slime-mega-A
Jun 7, 2026

Conversation

@aoshen02

@aoshen02 aoshen02 commented Jun 3, 2026

Copy link
Copy Markdown
Collaborator

PR-A — rollout data-model + train-split (RFC #107)

Heaviest-logic mega-PR. Ports the coupled rollout-data-model feature line from THUDM/slime.

Included

  • #1926 move micro-batch scheduling train→rollout side (vime/utils/dp_schedule.py, first-fit packing in seqlen_balancing.py, index-only DataIterator).
  • #1930 + #1933 variable global batch size + per-token-loss reduction fix (cp_utils.reduce_train_step_metrics / get_sum_of_sample_mean(sample_denoms=...); loss denominator → step_global_batch_size).
  • #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 raw mode. #1941 multi-sample fanout test. #1984 rename rollout_ids→group_ids (non-agent files; agent half → PR-D). #1962 lint.

Validation (CPU)

  • py_compile clean.
  • test_metric_report_dist + test_loss_cp_invariance + test_cp_utils + test_metric_report = 57/57 incl. real multi-process gloo distributed across CP/DP ∈ {1,2,4} — these assert CP-invariance and rollout-side per-rollout-mean == train-side train_one_step for the #1930/#1933 numerics. test_dp_schedule 8/8, test_sample 16/16.
  • GPU validation: stack-4 full matrix (this PR changes train numerics → high-info matrix).

Cross-PR note

test_sample reads args.vllm_speculative_config; relies on PR-C #1938's getattr guard (types.py). The integration stack order F+C+B+A satisfies this.

sglang→vLLM

Translated per the arg-map (--sglang-*→--vllm-*, sglang_rollout→vllm_rollout, vllm_speculative_config).

🤖 Generated with Claude Code


Fidelity ledger (audited 2026-06-04 vs slime 8ef1fb47..7a7aba4, via agent_run/scripts/completeness_oracle.sh)

op detail
Ported variable global-batch + per-token-loss + group_ids data model; CP per-token-loss reduction (cp_utils); the 6 numeric unit tests (dp_schedule/cp_utils/metric_report{,_dist}/loss_cp_invariance/sample)
Translated (sglang→vllm) _split_train_data_by_dp(data, dp_size)(data) reading dp_size from train_parallel_config + delegating to unit-testable dp_schedule.build_dp_schedule; --load-forge-rollout-data help reworded skip_sglang→skip_vllm / "sglang servers"→"vLLM servers, router, weight_update"
Dropped (faithful to slime) --disable-rollout-trim-samples + --use-dynamic-global-batch-size (slime #1933 removed them too)
Fixed in this audit (commit 8803d18) ported the missing tests/utils/test_hf_checkpoint_saver.py (slime #1969) + wired the 6 numeric tests + hf into the cpu CI job — they were present-but-unwired before
Verified cpu suite green on the rebuilt FCBAGDE stack; hf test ALL_PASS (gb200 job 8918)

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces support for compact/subagent fan-out patterns where a single rollout execution can emit multiple training samples sharing a single group ID. It implements a group-aware DP/microbatch scheduler, precomputes per-group mask sums to ensure correct loss denominators across micro-batches, and updates loss scaling and learning rate scheduling to use the actual step global batch size. Additionally, it adds a raw Megatron-to-HF checkpoint saver and comprehensive unit and end-to-end tests. Feedback from the review suggests interleaving micro-batch indices across virtual stages in VPP mode, replacing __getattribute__ overrides on Sample with standard properties to avoid performance overhead, guarding against division by zero in loss scaling, and supporting tuples in rollout output validation.

Comment on lines +254 to +258
def get_data_iterator(rollout_data: RolloutBatch) -> list[DataIterator]:
"""Build one ``DataIterator`` per VPP stage from the pre-computed schedule in ``rollout_data``."""
vpp_size = mpu.get_virtual_pipeline_model_parallel_world_size() or 1
micro_batch_indices = rollout_data["micro_batch_indices"]
return [DataIterator(rollout_data, micro_batch_indices) for _ in range(vpp_size)]

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.

high

In virtual pipeline parallel (VPP) training (vpp_size > 1), passing the same flat micro_batch_indices list to all DataIterator instances causes each virtual stage to process the exact same microbatches in the same order. This leads to duplicate data processing and incorrect training behavior.

To fix this, the microbatches should be interleaved across the virtual stages (e.g., micro_batch_indices[i::vpp_size] for stage i).

Suggested change
def get_data_iterator(rollout_data: RolloutBatch) -> list[DataIterator]:
"""Build one ``DataIterator`` per VPP stage from the pre-computed schedule in ``rollout_data``."""
vpp_size = mpu.get_virtual_pipeline_model_parallel_world_size() or 1
micro_batch_indices = rollout_data["micro_batch_indices"]
return [DataIterator(rollout_data, micro_batch_indices) for _ in range(vpp_size)]
def get_data_iterator(rollout_data: RolloutBatch) -> list[DataIterator]:
"""Build one ``DataIterator`` per VPP stage from the pre-computed schedule in ``rollout_data``."""
vpp_size = mpu.get_virtual_pipeline_model_parallel_world_size() or 1
micro_batch_indices = rollout_data["micro_batch_indices"]
return [DataIterator(rollout_data, micro_batch_indices[i::vpp_size]) for i in range(vpp_size)]

Comment thread vime/utils/types.py Outdated
Comment on lines +130 to +151
def __getattribute__(self, name):
if name == "rollout_id":
raise AttributeError("Sample.rollout_id is deprecated and write-only; use Sample.group_id instead.")
return object.__getattribute__(self, name)

def __setattr__(self, name, value):
if name == "group_id":
object.__setattr__(self, "group_id", value)
return
if name == "rollout_id":
# Deprecated assignment-only compatibility path. ``rollout_id`` is
# intentionally not a dataclass field and cannot be read.
if value is None:
return
warnings.warn(
"Sample.rollout_id is deprecated and write-only; set Sample.group_id instead.",
DeprecationWarning,
stacklevel=2,
)
object.__setattr__(self, "group_id", value)
return
object.__setattr__(self, name, value)

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.

high

Overriding __getattribute__ and __setattr__ to handle the deprecated rollout_id attribute introduces a significant performance overhead for every attribute access on Sample instances. In RL training, where millions of attributes are accessed, this can noticeably slow down data processing.

Using a standard Python property with a custom getter and setter achieves the exact same deprecation behavior with zero overhead for other attributes, and is much more idiomatic.

    @property
    def rollout_id(self):
        raise AttributeError("Sample.rollout_id is deprecated and write-only; use Sample.group_id instead.")

    @rollout_id.setter
    def rollout_id(self, value):
        if value is None:
            return
        warnings.warn(
            "Sample.rollout_id is deprecated and write-only; set Sample.group_id instead.",
            DeprecationWarning,
            stacklevel=2,
        )
        self.group_id = value

Comment on lines 1212 to 1218
if not args.calculate_per_token_loss:
loss = (
loss * num_microbatches / global_batch_size * mpu.get_data_parallel_world_size(with_context_parallel=True)
loss
* num_microbatches
/ step_global_batch_size
* mpu.get_data_parallel_world_size(with_context_parallel=True)
)

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.

medium

If step_global_batch_size is 0 (which can happen in distributed settings with empty partitions or heavy filtering), dividing by it will raise a ZeroDivisionError and crash the training run.

Consider guarding against division by zero by using max(step_global_batch_size, 1).

Suggested change
if not args.calculate_per_token_loss:
loss = (
loss * num_microbatches / global_batch_size * mpu.get_data_parallel_world_size(with_context_parallel=True)
loss
* num_microbatches
/ step_global_batch_size
* mpu.get_data_parallel_world_size(with_context_parallel=True)
)
if not args.calculate_per_token_loss:
loss = (
loss
* num_microbatches
/ max(step_global_batch_size, 1)
* mpu.get_data_parallel_world_size(with_context_parallel=True)
)

Comment thread vime/ray/rollout.py Outdated
Comment on lines +801 to +833
def _validate_group_id_annotated(node, depth=0):
"""Walk the rollout function's nested output and validate ``group_id`` only
when a compact / subagent pattern is detected.

"Compact" = the rollout function wraps multiple training samples from one
rollout execution into a ``list[Sample]``. In slime's convention the
default rollout shape is ``list[list[Sample]]`` (depth-2: prompt × rollout)
so its leaf ``list[Sample]`` lands at depth 1 and we skip validation,
preserving backward compatibility. A compact rollout adds a third level:
``list[list[list[Sample]]]`` (prompt × rollout × samples-from-one-group),
so the leaf ``list[Sample]`` lands at depth ≥ 2. At that point we require
every sibling to carry a non-None ``group_id`` (or legacy ``rollout_id``)
and to share the same value, so the loss reducer counts the group once
instead of N times.
"""
if isinstance(node, Sample):
return
assert isinstance(node, list), f"unexpected rollout output node type: {type(node).__name__}"
if node and isinstance(node[0], Sample):
if depth >= 2 and len(node) > 1:
group_ids = [s.group_id for s in node]
missing = [i for i, group_id in enumerate(group_ids) if group_id is None]
assert not missing, (
f"Compact rollout returned {len(node)} samples but group_id is unset on "
f"positions {missing}. Set Sample.group_id on every sibling so the loss "
"reducer can aggregate them as one group instead of N."
)
assert (
len(set(group_ids)) == 1
), f"Sibling samples from one compact rollout must share group_id; got {group_ids}."
return
for item in node:
_validate_group_id_annotated(item, depth + 1)

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.

medium

Strictly asserting isinstance(node, list) can cause unexpected crashes if a custom rollout function returns a tuple of Samples (which is common in Python). Supporting both list and tuple makes the validation much more robust.

def _validate_group_id_annotated(node, depth=0):
    """Walk the rollout function's nested output and validate ``group_id`` only
    when a compact / subagent pattern is detected.

    "Compact" = the rollout function wraps multiple training samples from one
    rollout execution into a ``list[Sample]``. In slime's convention the
    default rollout shape is ``list[list[Sample]]`` (depth-2: prompt × rollout)
    so its leaf ``list[Sample]`` lands at depth 1 and we skip validation,
    preserving backward compatibility. A compact rollout adds a third level:
    ``list[list[list[Sample]]]`` (prompt × rollout × samples-from-one-group),
    so the leaf ``list[Sample]`` lands at depth ≥ 2. At that point we require
    every sibling to carry a non-None ``group_id`` (or legacy ``rollout_id``)
    and to share the same value, so the loss reducer counts the group once
    instead of N times.
    """
    if isinstance(node, Sample):
        return
    assert isinstance(node, (list, tuple)), f"unexpected rollout output node type: {type(node).__name__}"
    if node and isinstance(node[0], Sample):
        if depth >= 2 and len(node) > 1:
            group_ids = [s.group_id for s in node]
            missing = [i for i, group_id in enumerate(group_ids) if group_id is None]
            assert not missing, (
                f"Compact rollout returned {len(node)} samples but group_id is unset on "
                f"positions {missing}. Set Sample.group_id on every sibling so the loss "
                "reducer can aggregate them as one group instead of N."
            )
            assert (
                len(set(group_ids)) == 1
            ), f"Sibling samples from one compact rollout must share group_id; got {group_ids}."
        return
    for item in node:
        _validate_group_id_annotated(item, depth + 1)

@aoshen02
aoshen02 force-pushed the sync/slime-mega-A branch from 8803d18 to 68d40fa Compare June 5, 2026 08:23
aoshen02 added a commit that referenced this pull request Jun 5, 2026
…ang->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>
aoshen02 added a commit that referenced this pull request Jun 5, 2026
…/#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>
aoshen02 added a commit that referenced this pull request Jun 6, 2026
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.
aoshen02 added a commit that referenced this pull request Jun 6, 2026
…/#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>
aoshen02 added a commit that referenced this pull request Jun 6, 2026
…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.
aoshen02 added a commit that referenced this pull request Jun 6, 2026
…ang->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>
aoshen02 added a commit that referenced this pull request Jun 6, 2026
…no image rebuild

Port THUDM/slime delta weight sync to vime's vLLM rollout. Trainer bytewise-diffs
weights vs a pinned-CPU snapshot and ships only changed positions+values (nccl
broadcast or disk safetensors); receiver overwrites only the changed bytes
(lossless, NaN-masked). Bandwidth optimization for large / cross-DC non-colocate.

- delta_io.py: DeltaEncoding/DeltaParam/DeltaSpec (local; slime imported from sglang io_struct).
- update_weight_from_distributed_delta.py: trainer encoder (subclasses UpdateWeightFromDistributed).
- delta_receiver.py: engine-agnostic pure-torch decode + NaN-masked apply
  (param_storage_index / delta_apply_context monkey-patches torch.Tensor.copy_/fill_
  scoped to model param storage, wrapping a normal model.load_weights).
- vLLMColocateWorkerExtension: collective_rpc-callable delta receivers (nccl: recv
  positions/values on model_update_group; disk: read safetensors). NO image rebuild
  -- receiver is runtime worker-extension/hijack, like the existing IPC hijack.
- args: --update-weight-mode/transport/encoding/delta-dir/keep-files/chunk-bytes.
- actor.py: delta-mode dispatch (lazy import, #1946 backward-compat) + zero-delta version bump.
- docs/zh/advanced/delta-weight-sync.md (+toctree) + e2e test test_delta_weight_update.py (CI registered).

SKIPPED: #1993 (sglang EAGLE draft-worker delta forwarding) = N/A, no vime/vLLM analogue.
CAVEAT (documented): vLLM does not refresh EAGLE/MTP draft weights on ANY sync (main-model
only) -- vLLM-wide limitation, not delta-specific; upstream-track.
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>
CalvinXKY pushed a commit that referenced this pull request Jun 7, 2026
* [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>
CalvinXKY pushed a commit that referenced this pull request Jun 7, 2026
…/#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>
aoshen02 added a commit that referenced this pull request Jun 7, 2026
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.
aoshen02 added a commit that referenced this pull request Jun 7, 2026
* [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>
@aoshen02
aoshen02 force-pushed the sync/slime-mega-A branch from ce6b409 to 73263b6 Compare June 7, 2026 14:01
aoshen02 added a commit that referenced this pull request Jun 7, 2026
…/#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>
aoshen02 and others added 5 commits June 7, 2026 14:06
…le 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>
…u 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>
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), 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>
…/#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>
@aoshen02
aoshen02 force-pushed the sync/slime-mega-A branch from 73263b6 to 3ec7c48 Compare June 7, 2026 14:08
aoshen02 added a commit that referenced this pull request Jun 7, 2026
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.
aoshen02 added a commit that referenced this pull request Jun 7, 2026
…no image rebuild

Port THUDM/slime delta weight sync to vime's vLLM rollout. Trainer bytewise-diffs
weights vs a pinned-CPU snapshot and ships only changed positions+values (nccl
broadcast or disk safetensors); receiver overwrites only the changed bytes
(lossless, NaN-masked). Bandwidth optimization for large / cross-DC non-colocate.

- delta_io.py: DeltaEncoding/DeltaParam/DeltaSpec (local; slime imported from sglang io_struct).
- update_weight_from_distributed_delta.py: trainer encoder (subclasses UpdateWeightFromDistributed).
- delta_receiver.py: engine-agnostic pure-torch decode + NaN-masked apply
  (param_storage_index / delta_apply_context monkey-patches torch.Tensor.copy_/fill_
  scoped to model param storage, wrapping a normal model.load_weights).
- vLLMColocateWorkerExtension: collective_rpc-callable delta receivers (nccl: recv
  positions/values on model_update_group; disk: read safetensors). NO image rebuild
  -- receiver is runtime worker-extension/hijack, like the existing IPC hijack.
- args: --update-weight-mode/transport/encoding/delta-dir/keep-files/chunk-bytes.
- actor.py: delta-mode dispatch (lazy import, #1946 backward-compat) + zero-delta version bump.
- docs/zh/advanced/delta-weight-sync.md (+toctree) + e2e test test_delta_weight_update.py (CI registered).

SKIPPED: #1993 (sglang EAGLE draft-worker delta forwarding) = N/A, no vime/vLLM analogue.
CAVEAT (documented): vLLM does not refresh EAGLE/MTP draft weights on ANY sync (main-model
only) -- vLLM-wide limitation, not delta-specific; upstream-track.
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>

@CalvinXKY CalvinXKY left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM

@CalvinXKY
CalvinXKY merged commit 879a398 into main Jun 7, 2026
11 of 14 checks passed
@aoshen02
aoshen02 deleted the sync/slime-mega-A branch June 8, 2026 14:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants