fix(reward): trainer adapters live in openadapt_evals.reward; flow keeps the worker and the client - #453
Merged
Merged
Conversation
…eps the worker and the client Remove trl_reward_function, verl_compute_score, UNSCORED_REWARD, is_unscored, drop_unscored and scored_groups from openadapt_flow.reward.callables. TRL's GRPOTrainer turns a None reward into NaN, combines per-function rewards with nansum, and takes the group mean over the result, so with one reward function an unscored episode trained as 0.0, which the reward contract forbids. verl's per-sample compute_score hook has no sentinel at all. The canonical adapters are openadapt_evals.reward.trl.CertifiedRewardFunction and openadapt_evals.reward.verl.CertifiedRewardManager (openadapt-evals >= 0.96.0), which fill an unscored episode with the mean of its scored group-mates so its advantage is exactly zero. openadapt-evals depends on openadapt-flow, so flow cannot import them and does not add the dependency. flow keeps HttpRewardClient (now with an injectable httpx transport), episode_from_columns, scalar_of and the RewardScorer protocol. Tests assert the module exposes no trainer adapter and round-trip the client against the worker. Docs and README point at the evals adapters and say why. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The API reference adds label_model to the five in the guide. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
openadapt_flow.reward.callablesno longer offers a trainer-facing reward function.trl_reward_function,verl_compute_score,UNSCORED_REWARD,is_unscored,drop_unscoredandscored_groupsare gone. The module keepsHttpRewardClient(now with an injectablehttpxtransport for tests),episode_from_columns,scalar_ofand theRewardScorerprotocol: the pieces a trainer node needs to reach a worker over HTTP.docs/REWARD_WORKER.mdand the README reward section now point atopenadapt_evals.reward(pip install 'openadapt-evals>=0.96.0') for the TRL and verl adapters, and say why. The "what runs where" table is unchanged. The wording matches https://docs.openadapt.ai/commercial/seal-reward/.The
rewardextra inpyproject.tomllisted neithertrlnorverl, so nothing changed there.Why
The flow TRL adapter returned
Nonefor an unscored episode and the verl adapter returned NaN. TRL'sGRPOTrainerturns aNonereward into NaN, combines the per-function rewards withnansum, and takes the group mean over the result. With one reward function that row trains as reward 0.0. The reward contract forbids 0.0 forreconciliation_requiredandfailed_platform: an unscored episode is dropped, never paid 0.openadapt_evals.reward.trl.CertifiedRewardFunctionandopenadapt_evals.reward.verl.CertifiedRewardManager(openadapt-evals 0.96.0, openadapt-evals#326) drop an unscored episode the one way a per-completion scalar allows. The episode gets the mean reward of its scored group-mates, so its GRPO advantage is exactly zero and the scored mean is unchanged. Those are the canonical adapters.The dependency runs one way: openadapt-evals depends on openadapt-flow. flow cannot import the adapters, and a second copy here would drift. This PR adds no dependency on openadapt-evals.
What a reviewer checks
openadapt_flow/reward/callables.py: notrl_reward_function, nocompute_score, noUNSCORED_REWARD. The module docstring names the canonical adapters and states the TRLNoneto 0.0 fact.tests/test_reward_worker.py::test_callables_offer_no_trainer_adapterasserts the absence, with the reason in a comment beside it.test_episode_from_columns_matches_the_evals_descriptor_shapeandtest_http_reward_client_roundtripcover the pieces that stay. The flow payload carries the evals descriptor keys plusschema_version; the worker accepts both.docs/REWARD_WORKER.md"Trainer adapters" section and README lines 469 to 475.Integration check (report only, nothing committed in evals)
Scratch venv with this branch (
.[reward]) andopenadapt-evals==0.96.0. Startedopenadapt-flow serve-reward --seed-mockmed --port 8788and droveopenadapt_evals.reward.receipts.HttpRewardEndpointagainst it.patient-honest-0001):POST /v1/rewardsbody{"episode_id", "policy_checkpoint_id", "policy_update", "reward_contract_digest", "metadata": {"oracle_identity": {...}}}withAuthorization: Bearer. Worker answered 200 with{"receipt": ...}and no top-levelschema_version.parse_receiptaccepted it.assess_receipt:verified, scalar 1.0, certified true, scope synthetic, tier 2.metadata.runtime_signal: failed_platform; the seed has no unscored fixture of its own): 200,failed_platform, scalarNone,unscoredtrue. No 0.0 anywhere.One gap, not a shape mismatch:
CertifiedRewardFunctionbuilds its descriptors with nometadata, so it never sendsoracle_identity. Against a worker with no priorRewardWorker.begin_episoderegistration for the episode, the worker answers 422identity_missingand the adapter raisesRewardEndpointError. The worker has no HTTP route forbegin_episode, so today the environment must register the identity in-process on the worker before the rollout. Reported here for routing; not changed in this PR.Opened by an agent session, not the founder.
🤖 Generated with Claude Code