diff --git a/.github/workflows/pr-test.yml b/.github/workflows/pr-test.yml
index 0868048c8..0f34222ee 100644
--- a/.github/workflows/pr-test.yml
+++ b/.github/workflows/pr-test.yml
@@ -556,10 +556,10 @@ jobs:
env:
GITHUB_COMMIT_NAME: ${{ github.sha }}_${{ github.event.pull_request.number || 'non-pr' }}
WANDB_API_KEY: ${{ secrets.WANDB_API_KEY }}
- SLIME_TEST_ENABLE_INFINITE_RUN: ${{ (github.event_name == 'workflow_dispatch' && github.event.inputs.infinite_run) || 'false' }}
- SLIME_TEST_USE_DEEPEP: ${{ matrix.info.use_deepep || '0' }}
- SLIME_TEST_USE_FP8_ROLLOUT: ${{ matrix.info.use_fp8_rollout || '0' }}
- SLIME_TEST_ENABLE_EVAL: ${{ matrix.info.enable_eval || '1' }}
+ VIME_TEST_ENABLE_INFINITE_RUN: ${{ (github.event_name == 'workflow_dispatch' && github.event.inputs.infinite_run) || 'false' }}
+ VIME_TEST_USE_DEEPEP: ${{ matrix.info.use_deepep || '0' }}
+ VIME_TEST_USE_FP8_ROLLOUT: ${{ matrix.info.use_fp8_rollout || '0' }}
+ VIME_TEST_ENABLE_EVAL: ${{ matrix.info.enable_eval || '1' }}
steps:
- name: Checkout repository
diff --git a/examples/fully_async/README.md b/examples/fully_async/README.md
index cd71455a4..ac05e1779 100644
--- a/examples/fully_async/README.md
+++ b/examples/fully_async/README.md
@@ -1,46 +1,77 @@
-# Fully Asynchronous Rollout Example
+# Fully-Async Rollout Example
-This example shows a simple way to make rollout generation **fully asynchronous**: a single global worker is created once and then keeps running in the background, continuously pulling prompts and launching generation tasks. Training only needs to fetch already finished results. This removes the per‑step wait that happens in the normal synchronous style.
+End-to-end demo of vime's fully-async rollout path. A background asyncio
+worker keeps a fixed pool of in-flight generations across rollout boundaries,
+so the next training step doesn't wait for the slowest in-flight sample.
+The worker itself lives in `vime.rollout.fully_async_rollout`; this
+directory is just the launch script.
## Files
-The fully-async worker has been **promoted from this example into the core package** — it now lives in
-`vime/rollout/fully_async_rollout.py`. This directory keeps only the launch script:
-* `run-qwen3-4b-fully_async.sh`: example launch script with Qwen3‑4B.
-## Prerequisite
-First set up model & environment following the Qwen3-4B example.
+* `run-qwen3-4b-fully_async.sh` — fully-async demo with Qwen3-4B on
+ dapo-math-17k.
+
+## Prerequisites
+
+```
+/root/Qwen3-4B/ # HF checkpoint
+/root/Qwen3-4B_torch_dist/ # tools/convert_hf_to_torch_dist.py
+/path/to/dapo-math-17k.jsonl # set PROMPT_SET in the script
+```
+
+## Run
-## Quick Start
```bash
cd vime
bash examples/fully_async/run-qwen3-4b-fully_async.sh
```
-You should see log lines like:
+
+You should see:
+
```
-Creating new global async worker...
-Continuous async rollout worker started
+fully-async rollout 0: target=8 queue_warm=0
+fully-async rollout 0: done in ...s, queue_left=...
```
-## How It Works (Very Short)
-* First call: create `AsyncRolloutWorker` (thread + asyncio loop).
-* Loop keeps up to `--rollout-batch-size` tasks in flight using `generate_and_rm_group`.
-* Completed groups are pushed into a queue; caller drains until it has enough samples.
-* Worker is stopped automatically at process exit.
-
-## Limitations
-* No evaluation mode.
-* Ordering is best effort (sorted at the end by index).
-* Minimal error handling.
+## How To Plug Your Own Generate Into This
-## Config Differences (2 Key Points)
-To enable the fully async pattern there are only two changes compared to a normal run:
+Two pieces flip the standard pipeline into fully-async:
-1. Use the async training driver: `train_async.py` (not `train.py`).
+1. Use the async training driver: `python3 train_async.py` (not `train.py`).
2. Set the rollout function path:
- ```bash
- --rollout-function-path vime.rollout.fully_async_rollout.generate_rollout_fully_async
- ```
+ ```
+ --rollout-function-path vime.rollout.fully_async_rollout.generate_rollout_fully_async
+ ```
-Why is it still "fully" async although `train_async.py` itself schedules rollouts step‑by‑step?
+For custom per-sample logic, use vime's standard plug-in points — they
+work unchanged under fully-async:
+
+```
+--custom-generate-function-path your.module.generate # (args, sample, sampling_params) -> Sample | list[Sample]
+--custom-rm-path your.module.reward # (args, sample | list[Sample]) -> float | list[float]
+```
+
+See `examples/coding_agent_rl/` for a non-trivial example that plugs in a
+multi-turn agent this way.
+
+## Worker Internals (Very Short)
+
+* First call: create a process-wide `AsyncRolloutWorker` (thread + asyncio
+ loop). The worker is shared across all subsequent `generate_rollout`
+ calls so its queue stays warm.
+* Loop keeps up to `args.vllm_server_concurrency` tasks in flight using
+ `generate_and_rm_group`.
+* Completed groups land on an output queue; each `generate_rollout` call
+ drains until it has `rollout_batch_size` groups and returns them sorted
+ by `sample.index`.
+* Groups containing an `ABORTED` sample are pushed back into
+ `data_buffer.add_samples` instead of being shipped to training.
+* Worker is stopped automatically at process exit via `atexit`.
+
+## Limitations
-Because the real generation work is done by a **persistent background worker** created in `generate_rollout_fully_async`. Each call from `train_async.py` only drains already completed samples from the worker's output queue; the worker has been continuously generating since the first call. Thus rollout production (model inference) and training consume happen in parallel with minimal waiting.
+* No evaluation mode (would conflict with the continuous-running model).
+* Ordering across rollouts is best-effort — within a rollout, groups are
+ sorted by index before being handed to training.
+* TODO: partial-rollout-style resume for `ABORTED` trajectories is not
+ yet wired; for now the trajectory is re-queued and starts over.
diff --git a/examples/geo3k_vlm_multi_turn/env_geo3k.py b/examples/geo3k_vlm_multi_turn/env_geo3k.py
index 634e8593f..972f0d286 100644
--- a/examples/geo3k_vlm_multi_turn/env_geo3k.py
+++ b/examples/geo3k_vlm_multi_turn/env_geo3k.py
@@ -32,7 +32,7 @@ class Geo3kEnv(BaseInteractionEnv):
an `answer` argument. We run the math reward checker against the ground truth and
return feedback for wrong answers. The episode ends when the answer is correct,
when max_turns is reached, or when the response has no valid tool call; in the
- last case we still try to score a boxed/text answer, matching SkyRL's env.
+ last case we still try to score a boxed/text answer.
"""
def __init__(self, *, ground_truth: str | None = None, max_turns: int | None = None):
diff --git a/scripts/run-minimax-m2.sh b/scripts/run-minimax-m2.sh
index 44937f01c..95380db7c 100644
--- a/scripts/run-minimax-m2.sh
+++ b/scripts/run-minimax-m2.sh
@@ -34,8 +34,8 @@ BASE_DIR=${BASE_DIR:-"/root"}
CKPT_ARGS=(
--hf-checkpoint ${BASE_DIR}/MiniMax-M2.5
--ref-load ${BASE_DIR}/MiniMax-M2.5_torch_dist
- --load ${BASE_DIR}/MiniMax-M2.5_slime/
- --save ${BASE_DIR}/MiniMax-M2.5_slime/
+ --load ${BASE_DIR}/MiniMax-M2.5_vime/
+ --save ${BASE_DIR}/MiniMax-M2.5_vime/
--save-interval 20
--megatron-to-hf-mode raw
--model-name minimax_m2
diff --git a/scripts/run-qwen2.5-0.5B-reproducibility.sh b/scripts/run-qwen2.5-0.5B-reproducibility.sh
index fa4c4a6d8..fb753a97d 100644
--- a/scripts/run-qwen2.5-0.5B-reproducibility.sh
+++ b/scripts/run-qwen2.5-0.5B-reproducibility.sh
@@ -1,6 +1,8 @@
#!/bin/bash
# for rerun the task
+pkill -9 -f '[v]llm serve|VLL[M]::'
+sleep 3
ray stop --force
pkill -9 ray
pkill -9 python
@@ -13,12 +15,7 @@ set -ex
# will prevent ray from buffering stdout/stderr
export PYTHONUNBUFFERED=1
-# Bitwise reproduction depends on a fixed parallel/reduction layout, so the GPU
-# count is pinned here (matching the upstream recipe) rather than auto-detected.
-NUM_GPUS=8
-
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
-VIME_ROOT="$(cd -- "${SCRIPT_DIR}/.." &>/dev/null && pwd)"
source "${SCRIPT_DIR}/models/qwen2.5-0.5B.sh"
CKPT_ARGS=(
@@ -112,27 +109,21 @@ MISC_ARGS=(
)
# launch the master node of ray in container
-export MASTER_ADDR=${MASTER_ADDR:-"127.0.0.1"}
-ray start --head --node-ip-address ${MASTER_ADDR} --num-gpus ${NUM_GPUS} --disable-usage-stats --dashboard-host=0.0.0.0 --dashboard-port=8265
-
-# Build the runtime environment JSON with proper variable substitution.
-# The NCCL_ALGO / NVTE / CUBLAS settings below are required for bitwise determinism.
-RUNTIME_ENV_JSON="{
- \"env_vars\": {
- \"PYTHONPATH\": \"${VIME_ROOT}:/root/Megatron-LM/\",
- \"CUDA_DEVICE_MAX_CONNECTIONS\": \"1\",
- \"NCCL_ALGO\": \"Ring\",
- \"NVTE_ALLOW_NONDETERMINISTIC_ALGO\": \"0\",
- \"CUBLAS_WORKSPACE_CONFIG\": \":4096:8\"
- }
-}"
+ray start --head --node-ip-address 127.0.0.1 --num-gpus 8 --disable-usage-stats
ray job submit --address="http://127.0.0.1:8265" \
- --runtime-env-json="${RUNTIME_ENV_JSON}" \
+ --runtime-env-json='{
+ "env_vars": {
+ "PYTHONPATH": "/root/Megatron-LM",
+ "CUDA_DEVICE_MAX_CONNECTIONS": "1",
+ "NCCL_ALGO": "Ring",
+ "NVTE_ALLOW_NONDETERMINISTIC_ALGO": "0",
+ "CUBLAS_WORKSPACE_CONFIG": ":4096:8"
+ }
+ }' \
-- python3 train.py \
- --train-backend megatron \
--actor-num-nodes 1 \
- --actor-num-gpus-per-node ${NUM_GPUS} \
+ --actor-num-gpus-per-node 8 \
--colocate \
--calculate-per-token-loss \
${MODEL_ARGS[@]} \
diff --git a/tests/test_agent_adapters.py b/tests/test_agent_adapters.py
index 94e055f67..c234b4c32 100644
--- a/tests/test_agent_adapters.py
+++ b/tests/test_agent_adapters.py
@@ -109,16 +109,16 @@ def flush() -> None:
def test_session_id_comes_from_protocol_fields_not_custom_header():
assert (
openai._request_session_id(
- FakeRequest({"X-Slime-Session-Id": "custom"}),
+ FakeRequest({"X-Vime-Session-Id": "custom"}),
{"metadata": {"session_id": "meta-session"}, "user": "body-user"},
)
== "meta-session"
)
assert (
- openai._request_session_id(FakeRequest({"X-Slime-Session-Id": "custom"}), {"user": "body-user"}) == "body-user"
+ openai._request_session_id(FakeRequest({"X-Vime-Session-Id": "custom"}), {"user": "body-user"}) == "body-user"
)
assert (
- anthropic._request_session_id(FakeRequest({"X-Slime-Session-Id": "custom", "X-Api-Key": "anthropic-key"}))
+ anthropic._request_session_id(FakeRequest({"X-Vime-Session-Id": "custom", "X-Api-Key": "anthropic-key"}))
== "anthropic-key"
)
assert (
@@ -138,7 +138,7 @@ def test_anthropic_translation_keeps_tool_results_and_tool_schema():
"content": [
{"type": "thinking", "thinking": "plan"},
{"type": "text", "text": "ok"},
- {"type": "tool_use", "name": "lookup", "input": {"q": "slime"}},
+ {"type": "tool_use", "name": "lookup", "input": {"q": "vime"}},
],
},
{"role": "user", "content": [{"type": "tool_result", "tool_use_id": "u1", "content": "result"}]},
@@ -156,7 +156,7 @@ def test_anthropic_translation_keeps_tool_results_and_tool_schema():
"role": "assistant",
"content": "ok",
"reasoning_content": "plan",
- "tool_calls": [{"function": {"name": "lookup", "arguments": {"q": "slime"}}}],
+ "tool_calls": [{"function": {"name": "lookup", "arguments": {"q": "vime"}}}],
},
{"role": "tool", "content": "result"},
]
@@ -185,7 +185,7 @@ def test_openai_translation_and_responses_input_shapes():
{
"id": "call_1",
"type": "function",
- "function": {"name": "lookup", "arguments": {"q": "slime"}},
+ "function": {"name": "lookup", "arguments": {"q": "vime"}},
}
],
},
@@ -210,7 +210,7 @@ def test_openai_translation_and_responses_input_shapes():
{
"id": "call_1",
"type": "function",
- "function": {"name": "lookup", "arguments": '{"q": "slime"}'},
+ "function": {"name": "lookup", "arguments": '{"q": "vime"}'},
}
],
},
@@ -313,7 +313,7 @@ async def fake_generate(prompt_ids, session, body, app, **kwargs):
async def run_case():
monkeypatch.setattr(openai, "_generate", fake_generate)
- raw = "use it slime"
+ raw = "use it vime"
tokenizer = ToyTokenizer({(451,): raw})
adapter = openai.OpenAIAdapter(tokenizer=tokenizer, vllm_url="http://unused")
adapter.open_session("sid-chat-tool-stream", sampling_defaults={"max_new_tokens": 8})
@@ -350,7 +350,7 @@ async def run_case():
assert any(c["choices"][0]["delta"] == {"content": "use it"} for c in chunks)
assert tool_delta["tool_calls"][0]["index"] == 0
assert tool_delta["tool_calls"][0]["function"]["name"] == "lookup"
- assert tool_delta["tool_calls"][0]["function"]["arguments"] == '{"query": "slime"}'
+ assert tool_delta["tool_calls"][0]["function"]["arguments"] == '{"query": "vime"}'
assert chunks[-1]["choices"][0]["finish_reason"] == "tool_calls"
assert segments[0].response_ids == [451]
@@ -364,7 +364,7 @@ async def fake_generate(prompt_ids, session, body, app, **kwargs):
async def run_case():
monkeypatch.setattr(openai, "_generate", fake_generate)
- raw = "look slime"
+ raw = "look vime"
tokenizer = ToyTokenizer({(301,): raw})
adapter = openai.OpenAIAdapter(tokenizer=tokenizer, vllm_url="http://unused")
adapter.open_session("sid-responses", sampling_defaults={"max_new_tokens": 8})
@@ -399,7 +399,7 @@ async def run_case():
assert output_types == ["message", "function_call"]
assert data["output"][0]["content"][0]["text"] == "look"
assert function_call["name"] == "lookup"
- assert function_call["arguments"] == '{"query": "slime"}'
+ assert function_call["arguments"] == '{"query": "vime"}'
assert segments[0].response_ids == [301]
asyncio.run(run_case())
@@ -414,7 +414,7 @@ async def fake_generate(prompt_ids, session, body, app, **kwargs):
async def run_case():
monkeypatch.setattr(openai, "_generate", fake_generate)
- raw = "slime"
+ raw = "vime"
tokenizer = ToyTokenizer({(551,): raw})
adapter = openai.OpenAIAdapter(tokenizer=tokenizer, vllm_url="http://unused")
adapter.open_session("sid-responses-tool-stream", sampling_defaults={"max_new_tokens": 8})
@@ -450,7 +450,7 @@ async def run_case():
assert created["type"] == "response.created"
assert [item["type"] for item in created["response"]["output"]] == ["function_call"]
assert completed_call["name"] == "lookup"
- assert completed_call["arguments"] == '{"query": "slime"}'
+ assert completed_call["arguments"] == '{"query": "vime"}'
assert segments[0].response_ids == [551]
asyncio.run(run_case())
@@ -616,7 +616,7 @@ async def run_case():
upstream_server = TestServer(upstream_app)
await upstream_server.start_server()
- tool_raw = "slime"
+ tool_raw = "vime"
tokenizer = ScriptedTokenizer(
prompts=[
[10, 11],
@@ -637,7 +637,7 @@ async def run_case():
headers={"Authorization": "Bearer sid-openai-token"},
json={
"model": "actor",
- "input": "find slime",
+ "input": "find vime",
"max_output_tokens": 5,
"tools": [
{
@@ -657,12 +657,12 @@ async def run_case():
json={
"model": "actor",
"input": [
- {"role": "user", "content": "find slime"},
+ {"role": "user", "content": "find vime"},
function_call,
{
"type": "function_call_output",
"call_id": function_call["call_id"],
- "output": "found slime",
+ "output": "found vime",
},
],
"max_output_tokens": 7,
@@ -684,7 +684,7 @@ async def run_case():
assert first.status == 200
assert second.status == 200
assert function_call["name"] == "lookup"
- assert function_call["arguments"] == '{"query": "slime"}'
+ assert function_call["arguments"] == '{"query": "vime"}'
assert second_data["output"][0]["content"][0]["text"] == "done"
assert [req["token_ids"] for req in upstream.requests] == [[10, 11], [10, 11, 20, 21, 30, 31]]
assert upstream.routing_keys == ["sid-openai-token", "sid-openai-token"]
@@ -712,7 +712,7 @@ async def run_case():
upstream_server = TestServer(upstream_app)
await upstream_server.start_server()
- tool_raw = "slime"
+ tool_raw = "vime"
tokenizer = ScriptedTokenizer(
prompts=[
[110, 111],
@@ -737,7 +737,7 @@ async def run_case():
json={
"model": "actor",
"max_tokens": 5,
- "messages": [{"role": "user", "content": [{"type": "text", "text": "find slime"}]}],
+ "messages": [{"role": "user", "content": [{"type": "text", "text": "find vime"}]}],
"tools": [
{
"name": "lookup",
@@ -756,7 +756,7 @@ async def run_case():
"model": "actor",
"max_tokens": 7,
"messages": [
- {"role": "user", "content": [{"type": "text", "text": "find slime"}]},
+ {"role": "user", "content": [{"type": "text", "text": "find vime"}]},
{"role": "assistant", "content": first_data["content"]},
{
"role": "user",
@@ -764,7 +764,7 @@ async def run_case():
{
"type": "tool_result",
"tool_use_id": tool_use["id"],
- "content": "found slime",
+ "content": "found vime",
}
],
},
@@ -786,7 +786,7 @@ async def run_case():
assert first.status == 200
assert second.status == 200
assert tool_use["name"] == "lookup"
- assert tool_use["input"] == {"query": "slime"}
+ assert tool_use["input"] == {"query": "vime"}
assert second_data["content"] == [{"type": "text", "text": "anthropic done"}]
assert [req["token_ids"] for req in upstream.requests] == [[110, 111], [110, 111, 120, 121, 130]]
assert upstream.routing_keys == ["sid-anthropic-token", "sid-anthropic-token"]
diff --git a/tests/test_agent_sdk_adapters.py b/tests/test_agent_sdk_adapters.py
index a4ad3d4ce..d947cd67a 100644
--- a/tests/test_agent_sdk_adapters.py
+++ b/tests/test_agent_sdk_adapters.py
@@ -52,7 +52,7 @@ async def fake_generate(prompt_ids, session, body, app, **kwargs):
monkeypatch.setattr(openai, "_generate", fake_generate)
tokenizer = SDKTokenizer(
[
- "slime",
+ "vime",
"final after tool",
]
)
@@ -82,7 +82,7 @@ def lookup(query: str) -> str:
model_settings=agents.ModelSettings(max_tokens=4),
)
try:
- result = await agents.Runner.run(agent, "find slime")
+ result = await agents.Runner.run(agent, "find vime")
finally:
await client.close()
await oai.close()
@@ -94,16 +94,16 @@ def lookup(query: str) -> str:
assert calls[0]["body"]["tools"][0]["name"] == "lookup"
assert calls[1]["body"]["input"][-1] == {
"call_id": calls[1]["body"]["input"][-2]["call_id"],
- "output": "found slime",
+ "output": "found vime",
"type": "function_call_output",
}
assert tokenizer.rendered[0][0] == [
{"role": "system", "content": "Use lookup."},
- {"role": "user", "content": "find slime"},
+ {"role": "user", "content": "find vime"},
]
assert tokenizer.rendered[1][0][-1] == {
"role": "tool",
- "content": "found slime",
+ "content": "found vime",
"tool_call_id": calls[1]["body"]["input"][-2]["call_id"],
}
assert segments[0].metadata["segment_kind"] == "final"
@@ -179,7 +179,7 @@ async def fake_generate(prompt_ids, session, body, app, **kwargs):
monkeypatch.setattr(openai, "_generate", fake_generate)
tokenizer = SDKTokenizer(
- ["streamed via sdk slime"]
+ ["streamed via sdk vime"]
)
adapter = openai.OpenAIAdapter(tokenizer=tokenizer, vllm_url="http://unused")
client = TestClient(TestServer(adapter.app))
@@ -233,7 +233,7 @@ async def fake_generate(prompt_ids, session, body, app, **kwargs):
segments = await adapter.finish_session("sdk-openai-chat-stream")
assert "".join(text_parts) == "streamed via sdk"
assert tool_names == ["lookup"]
- assert tool_arguments == ['{"query": "slime"}']
+ assert tool_arguments == ['{"query": "vime"}']
assert finish_reasons == ["tool_calls"]
assert usages[-1].prompt_tokens == 2
assert usages[-1].completion_tokens == 1
diff --git a/tests/test_cp_utils.py b/tests/test_cp_utils.py
index d37e870a7..3dfaefcad 100644
--- a/tests/test_cp_utils.py
+++ b/tests/test_cp_utils.py
@@ -15,7 +15,7 @@
from __future__ import annotations
-# Import the helpers BEFORE the slime imports so the megatron stub lands
+# Import the helpers BEFORE the vime imports so the megatron stub lands
# in sys.modules first. pytest's prepend importmode puts this file's
# directory (``tests/``) on sys.path, which is what makes the bare-name
# import work without an ``__init__.py``.
diff --git a/tests/test_loss_cp_invariance.py b/tests/test_loss_cp_invariance.py
index 998ba1d6c..9f83e0ae1 100644
--- a/tests/test_loss_cp_invariance.py
+++ b/tests/test_loss_cp_invariance.py
@@ -7,7 +7,7 @@
Why this matters
----------------
-Slime's loss prescaling + Megatron's per-mb scaling + DDP's grad
+Vime's loss prescaling + Megatron's per-mb scaling + DDP's grad
averaging compose into one big formula. Any time we touch any one of
those three layers the numbers should land in the same place. Until
this test existed we only had end-to-end report-formula checks
@@ -18,12 +18,12 @@
--------------------------
We reproduce, for each spawned rank, the exact sequence Megatron applies
when a 3-tuple ``(loss, num_tokens, log)`` comes back from the loss
-function with ``calculate_per_token_loss=False`` — slime's per-rollout-
+function with ``calculate_per_token_loss=False`` — vime's per-rollout-
mean path:
1. Loss function pre-scales::
loss *= num_microbatches / step_global_batch_size * (dp * cp)
- See ``slime/backends/megatron_utils/loss.py:1209-1215``.
+ See ``vime/backends/megatron_utils/loss.py:1209-1215``.
2. Megatron divides by ``clamp(num_tokens, 1)`` then by
``num_microbatches``::
output_tensor /= torch.clamp(num_tokens, min=1) # num_tokens=1 → no-op
@@ -45,7 +45,7 @@
What this test does NOT exercise: the actual Megatron model classes, the
real DDP buffer code, fused optimizers, mixed-precision. We use a plain
``nn.Linear`` with manual all-reduce-average to simulate steps 1-4 above.
-The contract here is on *our* scaling math (steps 1 + 4 are slime's;
+The contract here is on *our* scaling math (steps 1 + 4 are vime's;
step 2 is what Megatron does to our 3-tuple). If Megatron later changes
step 2 — e.g. drops the ``/= num_microbatches`` — this test won't catch
it, but the real GPU integration suite (``test_qwen2.5_0.5B_short.py``)
@@ -54,7 +54,7 @@
from __future__ import annotations
-# Megatron stub must land in sys.modules first; the slime imports inside
+# Megatron stub must land in sys.modules first; the vime imports inside
# the worker pick it up via this same module. pytest's prepend importmode
# puts ``tests/`` on sys.path so the bare-name import works without an
# ``__init__.py``; mp.spawn children inherit the parent's sys.path.
@@ -85,8 +85,8 @@ def _grad_norm_worker(
"""One spawned rank.
Builds a tiny ``nn.Linear`` model (deterministic init via ``seed``),
- runs slime's per-rollout-mean loss reducer with the rank's share of
- the four-rollout fixture, applies the slime-side prescaling, then
+ runs vime's per-rollout-mean loss reducer with the rank's share of
+ the four-rollout fixture, applies the vime-side prescaling, then
Megatron's per-mb scaling, then ``.backward()``, then a manual
all-reduce-average across the dp-with-cp group (mirroring DDP's
``average_in_collective=False`` path with
@@ -151,7 +151,7 @@ def _grad_norm_worker(
reducer = get_sum_of_sample_mean(my_tl, my_rl, my_masks, my_denoms)
loss = reducer(output)
- # === Step 1: slime's per-rollout-mean prescaling ======================
+ # === Step 1: vime's per-rollout-mean prescaling ======================
# loss.py:1209-1215. ``mpu.get_data_parallel_world_size(with_context_parallel=True)``
# is the dp-with-cp world size, which is ``world_size`` in this setup.
loss = loss * num_microbatches / step_global_batch_size * world_size
@@ -160,10 +160,10 @@ def _grad_norm_worker(
# schedules.py:258-264 — for the 3-tuple, not-per-token-loss path:
# output_tensor /= torch.clamp(num_tokens, min=1)
# output_tensor /= num_microbatches
- # slime passes num_tokens=1 in this path (loss.py:1221), so the
+ # vime passes num_tokens=1 in this path (loss.py:1221), so the
# first divide is a no-op; we keep it explicit to mirror the
# source faithfully.
- num_tokens_for_scaling = torch.tensor(1.0) # slime's placeholder
+ num_tokens_for_scaling = torch.tensor(1.0) # vime's placeholder
loss = loss / torch.clamp(num_tokens_for_scaling, min=1.0)
loss = loss / num_microbatches
@@ -218,7 +218,7 @@ def _run_grad_norm_worker(dp_size: int, cp_size: int, tmp_path) -> float:
# - (1, 4) deeper CP-only
# - (4, 1) deeper DP-only
# The full 3*3 matrix lives in test_metric_report_dist.py — here we just
-# want enough coverage to catch a sign/factor regression in the slime
+# want enough coverage to catch a sign/factor regression in the vime
# prescaling math.
_PARALLELISM_CASES = [(1, 1), (2, 1), (1, 2), (2, 2), (1, 4), (4, 1)]
diff --git a/tests/test_metric_report.py b/tests/test_metric_report.py
index 98d7d69c6..8f3f9d753 100644
--- a/tests/test_metric_report.py
+++ b/tests/test_metric_report.py
@@ -17,7 +17,7 @@
from __future__ import annotations
-# Import the helpers BEFORE the slime imports so the megatron stub lands
+# Import the helpers BEFORE the vime imports so the megatron stub lands
# in sys.modules first. pytest's prepend importmode puts this file's
# directory (``tests/``) on sys.path, which is what makes the bare-name
# import work without an ``__init__.py``.
diff --git a/tests/test_metric_report_dist.py b/tests/test_metric_report_dist.py
index 7535027aa..cd1681832 100644
--- a/tests/test_metric_report_dist.py
+++ b/tests/test_metric_report_dist.py
@@ -23,7 +23,7 @@
from __future__ import annotations
# IMPORTANT: import the helpers (and the megatron stub it installs) BEFORE
-# any slime import. Spawned workers re-import this module from scratch, so
+# any vime import. Spawned workers re-import this module from scratch, so
# the same ordering must hold there — see ``stub_megatron_in_worker``
# for the worker-side details. pytest's prepend importmode puts
# ``tests/`` on sys.path so the bare-name import works without an
@@ -295,7 +295,7 @@ def test_rollout_log_real_distributed_multi_key(dp_size, cp_size, tmp_path):
# Keep an explicit reference to silence "unused import" complaints while
# documenting that importing the helpers module is load-bearing (it
-# installs the megatron stub before slime is touched).
+# installs the megatron stub before vime is touched).
_ = _cp_dist_helpers
diff --git a/tests/test_qwen2.5_0.5B_fanout_short.py b/tests/test_qwen2.5_0.5B_fanout_short.py
index 01c5ddbb1..f902467e6 100644
--- a/tests/test_qwen2.5_0.5B_fanout_short.py
+++ b/tests/test_qwen2.5_0.5B_fanout_short.py
@@ -44,7 +44,7 @@
import vime.utils.external_utils.command_utils as U
-TIGHT_DEVICE_MEMORY = U.get_bool_env_var("SLIME_TEST_TIGHT_DEVICE_MEMORY", "1")
+TIGHT_DEVICE_MEMORY = U.get_bool_env_var("VIME_TEST_TIGHT_DEVICE_MEMORY", "1")
MODEL_NAME = "Qwen2.5-0.5B-Instruct"
MODEL_TYPE = "qwen2.5-0.5B"
@@ -54,8 +54,8 @@
# through to the Ray-submitted job via an env var so all worker
# processes write to the same path.
FANOUT_COUNTER_FILE = os.environ.get(
- "SLIME_FANOUT_TEST_COUNTER_FILE",
- os.path.join(tempfile.gettempdir(), "slime_fanout_test_counter.log"),
+ "VIME_FANOUT_TEST_COUNTER_FILE",
+ os.path.join(tempfile.gettempdir(), "vime_fanout_test_counter.log"),
)
@@ -190,7 +190,7 @@ def execute():
megatron_model_type=MODEL_TYPE,
# Make the counter path visible inside the Ray-submitted job
# (helper picks it up via os.environ).
- extra_env_vars={"SLIME_FANOUT_TEST_COUNTER_FILE": FANOUT_COUNTER_FILE},
+ extra_env_vars={"VIME_FANOUT_TEST_COUNTER_FILE": FANOUT_COUNTER_FILE},
)
# Post-train assertion: compact_generate must have been called exactly
diff --git a/tests/test_qwen3_4B_streaming_partial_rollout.py b/tests/test_qwen3_4B_streaming_partial_rollout.py
index 898e4c2cc..065f57222 100644
--- a/tests/test_qwen3_4B_streaming_partial_rollout.py
+++ b/tests/test_qwen3_4B_streaming_partial_rollout.py
@@ -20,7 +20,7 @@
import vime.utils.external_utils.command_utils as U
-TIGHT_HOST_MEMORY = U.get_bool_env_var("SLIME_TEST_TIGHT_HOST_MEMORY", "1")
+TIGHT_HOST_MEMORY = U.get_bool_env_var("VIME_TEST_TIGHT_HOST_MEMORY", "1")
MODEL_NAME = "Qwen3-4B"
MODEL_TYPE = "qwen3-4B"
diff --git a/vime/ray/rollout.py b/vime/ray/rollout.py
index 572f95514..7c1056f90 100644
--- a/vime/ray/rollout.py
+++ b/vime/ray/rollout.py
@@ -817,7 +817,7 @@ def _validate_rollout_id_annotated(node, depth=0):
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
+ rollout execution into a ``list[Sample]``. In vime'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:
diff --git a/vime/rollout/_fanout_test_helpers.py b/vime/rollout/_fanout_test_helpers.py
index 3590ca472..9080ff281 100644
--- a/vime/rollout/_fanout_test_helpers.py
+++ b/vime/rollout/_fanout_test_helpers.py
@@ -35,7 +35,7 @@
# Each invocation appends one line. The test file reads this after train
# completes to assert the framework actually drove the custom path for
# every prompt (no silent bypass / no double-submission).
-COUNTER_FILE_ENV = "SLIME_FANOUT_TEST_COUNTER_FILE"
+COUNTER_FILE_ENV = "VIME_FANOUT_TEST_COUNTER_FILE"
async def compact_generate(args, sample, sampling_params):
diff --git a/vime/utils/dp_schedule.py b/vime/utils/dp_schedule.py
index e30621ca5..283f8631b 100644
--- a/vime/utils/dp_schedule.py
+++ b/vime/utils/dp_schedule.py
@@ -2,7 +2,7 @@
Pure-Python logic that decides, for one rollout's worth of sample lengths,
how to group samples into micro-batches and which DP rank owns each mbs.
-Lives outside the ray/sglang-importing modules so it can be unit-tested
+Lives outside the ray/vllm-importing modules so it can be unit-tested
under CPU-only CI.
The scheduling philosophy is **pack first, distribute second**:
diff --git a/vime/utils/external_utils/command_utils.py b/vime/utils/external_utils/command_utils.py
index ae4e63981..6bab7d9b4 100644
--- a/vime/utils/external_utils/command_utils.py
+++ b/vime/utils/external_utils/command_utils.py
@@ -108,14 +108,8 @@ def execute_train(
master_addr = os.environ.get("MASTER_ADDR", "127.0.0.1")
exec_command(
- # vLLM renames its VRAM-holding subprocesses via set_process_title()
- # (VLLM::EngineCore, VLLM::Worker_TP*, vllm::router), so their cmdline no
- # longer contains "vllm serve". Matching only the launcher would leave the
- # engine/worker children holding GPU memory and leak it into the next run.
- # Match both the launcher and the renamed children; the [v]/[M] bracket
- # trick keeps this pattern from matching pkill's own cmdline. This targets
- # exactly the vLLM tree, so the old indiscriminate `pkill -9 python`
- # (dangerous on colocate/shared nodes) is no longer needed.
+ # vLLM renames its subprocesses (VLLM::EngineCore / Worker_TP*), so match
+ # the renamed children too; the [v]/[M] brackets avoid matching pkill itself.
"pkill -9 -f '[v]llm serve|VLL[M]::'; "
"sleep 3; "
f"{'' if external_ray else 'ray stop --force; '}"