Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
6913120
[RL] Add Batcher as Configurable, support [B, L] microbatches
wwwjn May 18, 2026
7c7c9f7
rebase
wwwjn May 18, 2026
8e4fc60
remove position in loss calc
wwwjn May 19, 2026
dc690a1
update algorithm
wwwjn May 19, 2026
40ef4c5
update rebase
wwwjn May 19, 2026
767022f
update trainer to using new TrainBatch
wwwjn May 20, 2026
50b5572
update loss
wwwjn May 20, 2026
86ed252
update names and configs
wwwjn May 20, 2026
31dcd8b
update batcher with waste metrics
wwwjn May 20, 2026
7dad6f5
update configs
wwwjn May 22, 2026
d440e46
address comments
wwwjn May 26, 2026
1523db5
v8 datatypes + env protocol
May 27, 2026
312c292
v8 rubric + rollouts refactor
May 27, 2026
14aaeca
v8 Task surface refactor + style pass
May 28, 2026
6292f1d
v8 docstring/style pass + truncation fix + renderer tokenizer
May 29, 2026
e9af27a
Merge upstream/main (landed batcher PR) into v8 branch
May 29, 2026
85880db
Fix NoReduce collision: rollout/group_failures sums across collection…
May 29, 2026
9243ba1
Adopt renderers typed-config API (create_renderer(tokenizer, config))
May 29, 2026
701b4d1
Revert unrelated merge drift to upstream/main
May 29, 2026
11003ba
RL rollout loop cleanup: RolloutGroup, per-rollout step, status enum
May 29, 2026
5044e86
RL example default: thinking on, max_tokens=700; tidy rollout types
May 29, 2026
2dcd0f9
RL env/types review pass (docs 69+70): renames, env reward, renderer …
May 29, 2026
7a72a41
Fix _build_episodes group-skip + rollout_to_episode text
May 29, 2026
0cf8460
Docstring concision pass + rename envs/ -> env_types/
May 29, 2026
df376bb
Make Task an ABC; base Config owns rubric, subclass builds it
May 30, 2026
d3ba2df
[rl] v8: message/token env types, Configurable rubric, Task ABC
Jun 2, 2026
de7c887
Refine RL rollout protocol
Jun 3, 2026
c2efd2b
Rename Task.Config.env_config -> env_wrapper_cfg
Jun 3, 2026
8b597ba
Merge remote-tracking branch 'upstream/main' into v8-datatypes-env-pr…
Jun 3, 2026
79c3903
[rl] address PR review (round 2): env/rollout naming + cleanups
Jun 3, 2026
621e3cf
[rl] PR review round 2: shape hints + Task->Rollouter rename
Jun 4, 2026
3c69ae6
[rl] PR review round 2: env/rollout/examples package layout
Jun 4, 2026
c77d47f
[rl] renderer: None-default knobs; build the typed config via create_…
Jun 4, 2026
75e69d4
Merge remote-tracking branch 'upstream/main' into v8-datatypes-env-pr…
Jun 4, 2026
80104f5
[rl] PR review round 3: naming (completion_message, MessageEnv*Output…
Jun 5, 2026
4bf9b33
[rl] PR review round 3: get_train_sample -> get_training_sample (tian…
Jun 5, 2026
9d91d4c
Merge branch 'main' of https://github.com/pytorch/torchtitan into v8-…
Jun 5, 2026
d33903e
[rl] token: simplify the history-edit TODO comment
Jun 5, 2026
89f8f85
[rl] rollout_to_episode: TODO for branching when multi-turn history d…
Jun 5, 2026
04c47c2
[rl] CI: install renderers in RL integration test workflows
Jun 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/integration_test_4gpu_rl.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,11 @@ jobs:
# Install uv for faster dependency resolution
pip install uv

# 1. Install Monarch and TorchStore
# 1. Install Monarch, TorchStore, and Renderers
uv pip install torchmonarch
uv pip install --no-deps "git+https://github.com/meta-pytorch/torchstore.git@main"
uv pip install pygtrie portpicker
uv pip install "git+https://github.com/PrimeIntellect-ai/renderers.git@main"

# 2. Install batch-invariant ops
uv pip install --no-deps "git+https://github.com/thinking-machines-lab/batch_invariant_ops.git@main"
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/integration_test_8gpu_rl_h100.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,11 @@ jobs:
# Install uv for faster dependency resolution
pip install uv

# 1. Install Monarch and TorchStore
# 1. Install Monarch, TorchStore, and Renderers
uv pip install torchmonarch
uv pip install --no-deps "git+https://github.com/meta-pytorch/torchstore.git@main"
uv pip install pygtrie portpicker
uv pip install "git+https://github.com/PrimeIntellect-ai/renderers.git@main"

# 2. Install batch-invariant ops
uv pip install --no-deps "git+https://github.com/thinking-machines-lab/batch_invariant_ops.git@main"
Expand Down
3 changes: 2 additions & 1 deletion torchtitan/experiments/rl/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@ uv venv --python 3.12 titan-rl
source titan-rl/bin/activate
```

1. Install Monarch and TorchStore from main:
1. Install Monarch, TorchStore, and Renderers from main:
```bash
uv pip install torchmonarch
uv pip install --no-deps "git+https://github.com/meta-pytorch/torchstore.git@main"
uv pip install pygtrie portpicker
uv pip install "git+https://github.com/PrimeIntellect-ai/renderers.git@main"

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.

would this be used for sft as well?

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.

Do we need to depend on renders lastest main?

```

2. Install Flash Attention 3 kernels:
Expand Down
42 changes: 27 additions & 15 deletions torchtitan/experiments/rl/actors/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,6 @@ def get_vllm_compilation_config(
class SamplingConfig:
"""Sampling parameters passed to vLLM's SamplingParams."""

n: int = 8
"""Number of completions to generate per prompt (vLLM SamplingParams.n)."""

temperature: float = 0.8
"""Sampling temperature. 0.0 = greedy, higher = more random."""

Expand Down Expand Up @@ -258,6 +255,7 @@ def __init__(
compile_config: CompileConfig,
max_num_seqs: int,
output_dir: str,
stop_token_ids: list[int],
):
init_logger()
sl.init_structured_logger(
Expand All @@ -275,9 +273,13 @@ def __init__(
# the upper bound for concurrent sequences, determines KV-cache
# block allocation (and therefore GPU memory usage), and bounds
# the CUDA graph capture sizes. Always computed by the caller
# (RLTrainer) as num_prompts_per_step * sampling.n.
# (RLTrainer) as num_groups_per_rollout_batch * group_size.
self._max_num_seqs = max_num_seqs

# Renderer role-boundary stop tokens (e.g. Qwen3 `<|im_end|>`), injected by the
# controller;
self._stop_token_ids = stop_token_ids

# Register TorchTitan model + parser with vLLM
registry_to_vllm(
model_spec,
Expand Down Expand Up @@ -388,17 +390,19 @@ async def generate(
self,
tokenized_prompts: list[list[int]],
*,
request_ids: list[str],
sampling_config: SamplingConfig | None = None,
metrics_prefix: str = "generator",
) -> tuple[list[Completion], list[m.Metric]]:
"""Generate completions and generator metrics for tokenized prompts.

Takes ``tokenized_prompts`` as ``[num_prompts][prompt_tokens]``.
Returns completions as ``[num_prompts * n]`` plus generator metrics,
where ``n`` is the resolved ``SamplingConfig.n`` completions per prompt.
Returns completions in the same order as ``request_ids`` plus generator
metrics.

Args:
tokenized_prompts: Tokenized prompts shaped ``[num_prompts][prompt_tokens]``.
request_ids: One id per prompt echoed on each ``Completion.request_id``.
sampling_config: Optional per-call override for the generator's
default SamplingConfig. ``seed`` always comes from
``config.debug.seed`` (not part of SamplingConfig).
Expand All @@ -419,22 +423,32 @@ async def generate(
temperature=_sampling_config.temperature,
top_p=_sampling_config.top_p,
max_tokens=_sampling_config.max_tokens,
n=_sampling_config.n,
n=1, # group_size pre-expands prompts; the RL loop always samples n=1
stop_token_ids=self._stop_token_ids or None,
seed=self.config.debug.seed,
logprobs=1,
output_kind=RequestOutputKind.FINAL_ONLY,
)

if len(request_ids) != len(tokenized_prompts):
raise ValueError(
f"got {len(request_ids)} request_ids for {len(tokenized_prompts)} prompts"
)
if len(set(request_ids)) != len(request_ids):
raise ValueError(f"request_ids must be unique; got {request_ids}")

# render_cmpl is vLLM's input-pipeline entry.
# The tokenize step is a no-op for already-tokenized prompts. The
# lower-level alternative is vllm.inputs.tokens_input; we use the
# high-level API to stay resilient to vLLM internal changes.
engine_inputs = self._engine.renderer.render_cmpl(
[{"prompt_token_ids": ids} for ids in tokenized_prompts]
)
for i, engine_input in enumerate(engine_inputs):
for engine_input, request_id in zip(
engine_inputs, request_ids, strict=True
):
self._engine.add_request(
request_id=str(i),
request_id=request_id,
prompt=engine_input,
params=sampling_params,
)
Expand All @@ -444,15 +458,14 @@ async def generate(
while self._engine.has_unfinished_requests():
all_outputs.extend(self._engine.step())

# vLLM may return requests out of order; sort by the integer
# request_id we assigned so prompt_idx lines up with the input.
all_outputs.sort(key=lambda o: int(o.request_id))
# Return completions in caller input order; the controller maps positionally.
request_order = {request_id: i for i, request_id in enumerate(request_ids)}
all_outputs.sort(key=lambda output: request_order[output.request_id])

completions: list[Completion] = []
generation_metrics: list[m.Metric] = []
output_token_counts: list[int] = []
for output in all_outputs:
prompt_idx = int(output.request_id)
generation_metrics.extend(
_prepare_generation_request_metrics(output, prefix=metrics_prefix)
)
Expand All @@ -465,8 +478,7 @@ async def generate(
completions.append(
Completion(
policy_version=self.policy_version,
prompt_idx=prompt_idx,
text=sample.text,
request_id=output.request_id,
token_ids=sample.token_ids,
token_logprobs=per_token_logprobs,
finish_reason=sample.finish_reason,
Expand Down
2 changes: 1 addition & 1 deletion torchtitan/experiments/rl/actors/trainer.py
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ async def forward_backward(
async def optim_step(self) -> OptimStepOutput:
"""Clip gradients, step optimizer + LR scheduler, return updated state."""
# TODO: Accept optional optimizer params (e.g. learning rate)
# to allow controller-owned schedules (see Tinker API).
# to allow controller-owned schedules.

# capture LR before step
current_lrs = self.lr_schedulers.schedulers[0].get_last_lr()
Expand Down
10 changes: 5 additions & 5 deletions torchtitan/experiments/rl/batcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,11 +230,11 @@ def _pack_episodes(self, episodes: list[Episode]) -> Iterator[dict]:
def _iterate_samples() -> Iterator[dict]:
for ep in episodes:
prompt_len = len(ep.prompt_token_ids)
response_len = len(ep.token_ids)
raw_ids = ep.prompt_token_ids + ep.token_ids
gen_lp = [0.0] * prompt_len + ep.token_logprobs
loss_mask = [False] * prompt_len + [True] * response_len
advantages = [0.0] * prompt_len + [ep.advantage] * response_len
completion_len = len(ep.completion_token_ids)

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.

Is "completion" more established than "response"?

My nit is "completion" doesn't correspond to "prompt" better than "response".

@felipemello1 felipemello1 Jun 4, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Both are common in vllm. Completion is a class.

My nit is "completion" doesn't correspond to "prompt" better than "response".

When I hear "completion", i know its talking about the InferenceEngine output. There is no ambiguity. I know its not tool results or env outputs or something else. It is about generated tokens.

Response should work well as well. It is what we used in Forge, but there is more room for ambiguity IMO.

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.

sounds ok for now

raw_ids = ep.prompt_token_ids + ep.completion_token_ids
gen_lp = [0.0] * prompt_len + ep.completion_logprobs
loss_mask = [False] * prompt_len + [True] * completion_len
advantages = [0.0] * prompt_len + [ep.advantage] * completion_len
sample = {
"input_ids": raw_ids[:-1],
"labels": raw_ids[1:],
Expand Down
68 changes: 29 additions & 39 deletions torchtitan/experiments/rl/config_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@
from torchtitan.experiments.rl.actors.generator import SamplingConfig, VLLMGenerator
from torchtitan.experiments.rl.actors.trainer import PolicyTrainer
from torchtitan.experiments.rl.batcher import BatchConfig, Batcher
from torchtitan.experiments.rl.examples.sum_digits import SumDigitsRollouter
from torchtitan.experiments.rl.grpo import GRPOLoss, RLTrainer
from torchtitan.experiments.rl.observability.metrics import MetricsProcessor
from torchtitan.experiments.rl.sum_digits import SumDigitsEnv
from torchtitan.experiments.rl.renderer import RendererConfig
from torchtitan.models.common.attention import FlexAttention
from torchtitan.models.qwen3 import model_registry
from torchtitan.protocols.model import ModelConfigConverter
Expand Down Expand Up @@ -74,13 +75,12 @@ def rl_grpo_qwen3_0_6b_varlen() -> RLTrainer.Config:
model_spec=model_registry("0.6B", attn_backend="varlen"),
hf_assets_path="torchtitan/experiments/rl/example_checkpoint/Qwen3-0.6B",
num_steps=10,
num_prompts_per_step=5,
num_groups_per_rollout_batch=5,

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.

I feel this should be in Rollouter config.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

wouldnt that break the symmetry with trainer? i.e. the controller is the know that knows batchsize, microbatchsize, max_seq_len to pack to, etc. It sounds to me that the rollouter produces rollouts, but its up to the controller to say how many.

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.

oh sorry this was a comment during early review that I wanted to delete later as I read more. But I forgot

num_validation_samples=20,
compile=CompileConfig(enable=True, backend="aot_eager"),
env=SumDigitsEnv.Config(seed=42, correctness_reward=1.0, format_reward=0.3),
validation_env=SumDigitsEnv.Config(
seed=99, correctness_reward=1.0, format_reward=0.3
),
rollouter=SumDigitsRollouter.Config(),
group_size=group_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.

similar

renderer=RendererConfig(name="qwen3", enable_thinking=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.

Why render related to a model name? Is it because it will use tokenizer path? Currently hf_assets_path is only used to local tokenizer. Can we move the tokenizer and tokenizer path under render?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Why render related to a model name? Is it because it will use tokenizer path?
yes

Currently hf_assets_path is only used to local tokenizer. Can we move the tokenizer and tokenizer path under render?
Not yet. They dont support users providing their own tokenizer yet, but they will soon.

metrics=MetricsProcessor.Config(enable_wandb=True),
batcher=Batcher.Config(
batch=BatchConfig(local_batch_size=2, global_batch_size=8, seq_len=2048),
Expand Down Expand Up @@ -115,37 +115,34 @@ def rl_grpo_qwen3_0_6b_varlen() -> RLTrainer.Config:
),
checkpoint=CheckpointManager.Config(enable=False),
sampling=SamplingConfig(
n=group_size,
temperature=0.8,
top_p=0.95,
max_tokens=100,
max_tokens=700,
),
),
)


def rl_grpo_qwen3_0_6b_flex() -> RLTrainer.Config:
"""GRPO training config for Qwen3-0.6B with flex attention (4 GPUs: 2 gen + 2 train)."""
spec = model_registry("0.6B", attn_backend="flex")
group_size = 8
return RLTrainer.Config(
model_spec=spec,
model_spec=model_registry("0.6B", attn_backend="flex"),
hf_assets_path="torchtitan/experiments/rl/example_checkpoint/Qwen3-0.6B",
num_steps=10,
num_prompts_per_step=5,
num_groups_per_rollout_batch=5,
num_validation_samples=20,
# TODO: add aot_eager compiling overall, today it doesn't work because
# we are missing mechanism to scoop Flex region to plug in inductor backend support
env=SumDigitsEnv.Config(seed=42, correctness_reward=1.0, format_reward=0.3),
validation_env=SumDigitsEnv.Config(
seed=99, correctness_reward=1.0, format_reward=0.3
),
rollouter=SumDigitsRollouter.Config(),
group_size=group_size,
renderer=RendererConfig(name="qwen3", enable_thinking=True),
metrics=MetricsProcessor.Config(enable_wandb=True),
batcher=Batcher.Config(
batch=BatchConfig(local_batch_size=2, global_batch_size=8, seq_len=2048),
),
trainer=PolicyTrainer.Config(
optimizer=OptimizersContainer.Config(lr=2e-6),
optimizer=default_adamw(lr=2e-6),
lr_scheduler=LRSchedulersContainer.Config(
warmup_steps=2,
decay_type="linear",
Expand Down Expand Up @@ -174,7 +171,6 @@ def rl_grpo_qwen3_0_6b_flex() -> RLTrainer.Config:
),
checkpoint=CheckpointManager.Config(enable=False),
sampling=SamplingConfig(
n=group_size,
temperature=0.8,
top_p=0.95,
max_tokens=100,
Expand Down Expand Up @@ -217,13 +213,12 @@ def rl_grpo_qwen3_1_7b() -> RLTrainer.Config:
model_spec=model_registry("1.7B", attn_backend="varlen"),
hf_assets_path="torchtitan/experiments/rl/example_checkpoint/Qwen3-1.7B",
num_steps=10,
num_prompts_per_step=5,
num_groups_per_rollout_batch=5,
num_validation_samples=20,
compile=CompileConfig(enable=True, backend="aot_eager"),
env=SumDigitsEnv.Config(seed=42, correctness_reward=1.0, format_reward=0.3),
validation_env=SumDigitsEnv.Config(
seed=99, correctness_reward=1.0, format_reward=0.3
),
rollouter=SumDigitsRollouter.Config(),
group_size=group_size,
renderer=RendererConfig(name="qwen3", enable_thinking=True),
metrics=MetricsProcessor.Config(enable_wandb=True),
batcher=Batcher.Config(
batch=BatchConfig(local_batch_size=2, global_batch_size=8, seq_len=2048),
Expand Down Expand Up @@ -259,10 +254,9 @@ def rl_grpo_qwen3_1_7b() -> RLTrainer.Config:
),
checkpoint=CheckpointManager.Config(enable=False),
sampling=SamplingConfig(
n=group_size,
temperature=0.8,
top_p=0.95,
max_tokens=100,
max_tokens=700,

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.

Will need to change batcher max_seq_length accordingly, otherwise all the samples will be dropped because they are longer than max_seq_length

),
),
)
Expand All @@ -275,13 +269,12 @@ def rl_grpo_qwen3_14b() -> RLTrainer.Config:
model_spec=model_registry("14B", attn_backend="varlen"),
hf_assets_path="torchtitan/experiments/rl/example_checkpoint/Qwen3-14B",
num_steps=10,
num_prompts_per_step=5,
num_groups_per_rollout_batch=5,
num_validation_samples=20,
compile=CompileConfig(enable=True, backend="aot_eager"),
env=SumDigitsEnv.Config(seed=42, correctness_reward=1.0, format_reward=0.3),
validation_env=SumDigitsEnv.Config(
seed=99, correctness_reward=1.0, format_reward=0.3
),
rollouter=SumDigitsRollouter.Config(),
group_size=group_size,
renderer=RendererConfig(name="qwen3", enable_thinking=True),
metrics=MetricsProcessor.Config(enable_wandb=True),
batcher=Batcher.Config(
batch=BatchConfig(local_batch_size=2, global_batch_size=8, seq_len=2048),
Expand Down Expand Up @@ -316,17 +309,16 @@ def rl_grpo_qwen3_14b() -> RLTrainer.Config:
),
checkpoint=CheckpointManager.Config(enable=False),
sampling=SamplingConfig(
n=group_size,
temperature=0.8,
top_p=0.95,
max_tokens=100,
max_tokens=700,
),
),
)


def rl_grpo_qwen3_0_6b_batch_invariant() -> RLTrainer.Config:
"""On-policy GRPO config for Qwen3-0.6B under same parallelism (4 GPUs: 2 gen + 2 train).
"""On-policy GRPO config for Qwen3-0.6B (4 GPUs: 2 gen + 2 train).

Enables deterministic + batch-invariant mode for true on-policy RL training.
"""
Expand All @@ -336,13 +328,12 @@ def rl_grpo_qwen3_0_6b_batch_invariant() -> RLTrainer.Config:
model_spec=model_registry("0.6B", attn_backend="varlen"),
hf_assets_path="torchtitan/experiments/rl/example_checkpoint/Qwen3-0.6B",
num_steps=10,
num_prompts_per_step=5,
num_groups_per_rollout_batch=5,
num_validation_samples=20,
compile=CompileConfig(enable=True, backend="aot_eager"),
env=SumDigitsEnv.Config(seed=42, correctness_reward=1.0, format_reward=0.3),
validation_env=SumDigitsEnv.Config(
seed=99, correctness_reward=1.0, format_reward=0.3
),
rollouter=SumDigitsRollouter.Config(),
group_size=group_size,
renderer=RendererConfig(name="qwen3", enable_thinking=True),
metrics=MetricsProcessor.Config(enable_wandb=True),
batcher=Batcher.Config(
batch=BatchConfig(local_batch_size=2, global_batch_size=8, seq_len=2048),
Expand Down Expand Up @@ -381,10 +372,9 @@ def rl_grpo_qwen3_0_6b_batch_invariant() -> RLTrainer.Config:
),
checkpoint=CheckpointManager.Config(enable=False),
sampling=SamplingConfig(
n=group_size,
temperature=0.8,
top_p=0.95,
max_tokens=100,
max_tokens=700,
),
debug=batch_invariant_config,
),
Expand Down
20 changes: 20 additions & 0 deletions torchtitan/experiments/rl/environment/__init__.py

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.

In general I would prefer full spelling over shorthand.

Could we do

  • rl/environments/message.py
  • rl/environments/renderer.py

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I wanted to signal somehow that those are "base" envs, not something like a SumDigitsEnvs, thats why i put env_types. I am cool with environments, but i still think that we should signal somehow that those are types. Any ideas?

@tianyu-l tianyu-l Jun 3, 2026

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.

I see. If we follow strictly the sft counterpart, for classes / interfaces you would expect users to implement, it probably should be

  • protocols/environments
  • protocols/rubrics
  • etc.

Meanwhile, components for things that torchtitan implement for you (but also overridable).

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree.

from torchtitan.experiments.rl.environment.message import (
MessageEnv,
MessageEnvInitOutput,
MessageEnvStepOutput,
)
from torchtitan.experiments.rl.environment.token import TokenEnv, TokenEnvOutput

__all__ = [
"MessageEnv",
"MessageEnvInitOutput",
"MessageEnvStepOutput",
"TokenEnv",
"TokenEnvOutput",
]
Loading
Loading