Repository navigation
feat(checkpoint): checkpoint Workplace Assistant sessions - #3894
Conversation
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
5c5b53b to
4a44fa9
Compare
87e1f0c to
207f588
Compare
207f588 to
afee845
Compare
4a44fa9 to
44260b9
Compare
afee845 to
6a3c667
Compare
44260b9 to
031e9f6
Compare
6a3c667 to
f3ade85
Compare
031e9f6 to
7948699
Compare
f3ade85 to
ca27fd2
Compare
7948699 to
4317d35
Compare
ca27fd2 to
f98be7a
Compare
4317d35 to
92c9aad
Compare
f98be7a to
beab099
Compare
8527bf1 to
fe6b109
Compare
f39aa55 to
17a509f
Compare
ce82ebf to
2b249aa
Compare
17a509f to
3baed96
Compare
3baed96 to
726383b
Compare
2b249aa to
1c4ed3c
Compare
726383b to
009480a
Compare
1c4ed3c to
a5a36f0
Compare
a354cb3 to
3a8ddf3
Compare
a5a36f0 to
3073950
Compare
3a8ddf3 to
dc6f470
Compare
3073950 to
5830891
Compare
dc6f470 to
d83a4e0
Compare
5830891 to
1923e7f
Compare
d83a4e0 to
9fd69f4
Compare
1923e7f to
63809c2
Compare
9fd69f4 to
31ad088
Compare
63809c2 to
c908576
Compare
31ad088 to
53aa609
Compare
c908576 to
9e7ab61
Compare
53aa609 to
9b5c297
Compare
Declare the Workplace Assistant resources server checkpoint_mode = "exported" and implement the three session hooks over each session's tool environment. Export encodes every in-memory table column by column, keeping dtypes, index labels, and the difference between empty CSV cells (NaN) and values a tool stored as None. Restore rebuilds every session before installing any, so one invalid state installs nothing. Export leaves out a session /verify already discarded, and retire drops the session's tool environment. /verify keeps the default "wait" mode because it discards the session. Ported from #2946 onto the v2 checkpoint hooks, without the execution-to-session index and identity lookups that v2 replaces with cookie session IDs. Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com>
|
🔄 Merge queue validation started! You can track the progress here: https://github.com/NVIDIA-NeMo/Gym/actions/runs/39343677971 |
|
🔄 Merge queue validation started! You can track the progress here: https://github.com/NVIDIA-NeMo/Gym/actions/runs/39344263376 |
|
Rollout evidence rerun on vLLM 0.29.0, the version Gym's The tree was Uninterrupted baseline. 40 rollouts, eight per task, gave a mean reward of 0.275. The email reply succeeded 8 of 8 times, the CRM status move 3 of 8 times, and the other three tasks never succeeded. That is the same pattern as on vLLM 0.24.0, where the email reply succeeded 7 of 8 times. There were no failed or masked rollouts and no tracebacks. Checkpoint, crash and restore. Two runs cut the checkpoint at different points. Each crashed every Gym process with
At the end of both runs, every participant was idle and the Workplace server held no sessions. No server log had a traceback. |
ananthsub/partial-ckpt-workplace-assistantmainfeature,area:env-infraWhat changed and why
Workplace Assistant used the default
restart_onlymode, so every rollout with a live Workplace session was a restart and started over from scratch after a crash. This PR lets those sessions be checkpointed and continued.checkpoint_mode = "exported"and implements the three session hooks over its per-session state. That state is the tool environment created at/seed_session: a set of in-memory pandas tables for email, calendar, analytics, project management, the customer relationship manager, and the company directory.export_session_statesencodes every table column by column. It keeps column dtypes, such as the booleanuser_engagedcolumn, and index labels, which matter because the analytics tool appends rows by label. It also keeps the difference between empty CSV cells, which load as NaN, and values a tool stored asNone. JSON writes both asnull, so NaN positions are listed separately. Encoding runs in a worker thread. Admission is closed during a commit, so no tool call changes the tables while they are encoded.restore_session_statesrebuilds every session's tool environment first and installs them only after all of them are valid. A state with missing or extra containers or tables, or with mismatched column lengths, raisesValueErrorand installs nothing./verifydiscards the session's tool environment in afinallyblock. If verify raises, the session is gone but the participant still tracks it, so the commit must not fail on it.retire_session_statedrops the session's tool environment.checkpoint_verifystays at the defaultwait. Verify computes the reward only from the response and the ground truth, but it deletes the session's state, so it is not replay-safe._TOOLKITS, instead of being repeated inseed_sessionandmcp_tools.How it works
Where this PR sits in the overall flow
The highlighted part is what this PR adds.
flowchart LR C["Controller<br/>NeMo RL, or rollout collection"] CO["Coordination<br/>prepare, commit, restore, resume,<br/>retire, forget"] K["Control plane on every server<br/>phases, lease, storage,<br/>retire: refuse, stop, free;<br/>forget"] subgraph G["One participant per Gym server"] E["Environment server<br/>episode steps"] M["Policy model<br/>held responses, generation cuts"] A["Agent<br/>sessions parked at boundaries"] R["Resources server<br/>session state"] end W["Inference worker<br/>stages cut prefixes"] D[("Checkpoint directory<br/>records, then manifest")] L[("Capture ledger<br/>retire and delete from #3938, #3939")] C --> CO --> K K --> E & M & A & R M --> W M --> L G --> D classDef this fill:#fde68a,stroke:#b45309,stroke-width:2px,color:#1f2937 class R thisOne checkpoint, a crash, and the restore, end to end:
This PR
Each session's tool environment is a set of tables. A checkpoint exports them whole, and a restore rebuilds them before any of them is installed.
Where this sits in the stack
This PR uses the resources server checkpoint participant from #3886, which has merged, and needs nothing else from the open part of the partial-rollout checkpointing stack. It is one of five PRs that port the environments the old stack checkpointed onto the new hooks. Workplace Assistant and the Gymnasium fix target
main, and Blackjack builds on the Gymnasium fix. Indirect prompt injection and proof refinement are still based on the end-to-end suite (#3889):ananthsub/partial-ckpt-workplace-assistant): feat(checkpoint): checkpoint Workplace Assistant sessions (this PR)ananthsub/partial-ckpt-gymnasium): fix(gymnasium): build Gymnasium servers on the shared resources server setupananthsub/partial-ckpt-blackjack): feat(checkpoint): export Blackjack game state for partial-rollout checkpoints (on the Gymnasium PR)ananthsub/partial-ckpt-indirect-prompt-injection): feat(checkpoint): export indirect prompt injection session stateananthsub/partial-ckpt-proof-refinement): feat(checkpoint): continue proof refinement agent turns from their boundariesRelationship to the old stack
execution_to_sessionmap and the identity lookups in the tool route and verify. The v2 hooks are keyed by the cookie session ID, so neither is needed.checkpoint:<rollout>:a<attempt>session IDs on restore. The restored session keeps its original cookie session ID.to_json(orient="split")and repaired types after reading the JSON back. That turned NaN intoNoneand lost the difference between them. The new encoding keeps it.checkpoint_test_app.py) and its test. Both depend on old-stack rollout identities and on the test agent from that PR.Issue
No tracking issue exists for this re-cut. The re-cut series and the old stack's PRs carry the discussion.
Validation
Run on this branch, on the current
main:RAY_TMPDIR=/tmp .venv/bin/python -m pytest -q resources_servers/workplace_assistant/tests: passed, including the newtests/test_checkpoint.py. Its tests drive the real control routes over ASGI:/verify. Tool outputs, every table, and the reward all match an uncheckpointed run of the same steps./verifyraised is left out of the export. The commit succeeds with only the live session, which then continues after restore.RAY_TMPDIR=/tmp .venv/bin/python -m pytest -q tests/unit_tests/test_checkpoint_*.py: passed.ruff checkandruff format --checkon the changed files: clean.pre-commit run --files <changed files>: all hooks passed.Signed-off-byline.Rollout evidence
Setup
The model was
Qwen/Qwen3-4B-Instruct-2507, served by vLLM 0.24.0 with thehermestool-call parser on one NVIDIA RTX 6000 Ada Generation (48 GB).Gym's
vllm_modelserver ran withuses_reasoning_parser=false, because the served model is an instruct model without a reasoning parser.Every rollout sampled at temperature 1.0, used the five tasks in
resources_servers/workplace_assistant/data/example.jsonl, and ran Simple Agent withmax_steps: 6behind the flat-row wrapper.Each tree ran in its own worktree, with server venvs created by
gym env start.Uninterrupted baseline
This change on
mainran with checkpointing off, eight rollouts per task:gym env start --config resources_servers/workplace_assistant/configs/workplace_assistant.yaml --model-type vllm_model \ --model Qwen/Qwen3-4B-Instruct-2507 --model-url http://127.0.0.1:8100/v1 --model-api-key dummy \ ++policy_model.responses_api_models.vllm_model.uses_reasoning_parser=false gym eval run --no-serve --config resources_servers/workplace_assistant/configs/workplace_assistant.yaml --model-type vllm_model \ --model Qwen/Qwen3-4B-Instruct-2507 --model-url http://127.0.0.1:8100/v1 --model-api-key dummy \ ++policy_model.responses_api_models.vllm_model.uses_reasoning_parser=false \ --agent workplace_assistant_simple_agent --input resources_servers/workplace_assistant/data/example.jsonl \ --output rollouts.jsonl --num-repeats 8 --concurrency 16 --temperature 1.0The 40 rollouts had a mean reward of 0.25.
By task, the email reply succeeded 7 of 8 times, the CRM status move 3 of 8 times, and the calendar rename and the two other CRM tasks never succeeded.
The same command on the checkpoint stack with this change, still with checkpointing off, also gave 0.25 over 40 rollouts.
Neither run had failed or masked rollouts or tracebacks in the server logs.
Checkpoint, crash and restore
The tree was the checkpoint stack (
ananthsub/partial-ckpt-e2e) with this change cherry-picked on top; it applied without conflicts.A driver built on the process-level checkpoint suite (
tests/e2e/checkpoint/checkpoint_deployment.py) started the policy model, the Workplace Assistant resources server, Simple Agent and the flat-row wrapper, each as its own process from its own venv.It sent the rollouts to the wrapper's
/runand drove the checkpoint throughnemo_gym._checkpoint.coordination, as a training controller would:SIGKILL, start fresh processes from the same configs, restore the committed episodes and resume.Four runs cut the checkpoint at different points, so that later cuts catch episodes after their state-changing tool calls:
Every prepare returned in 8 ms or less and reported no restarts.
Simple Agent reported every in-flight episode at a boundary, and the Workplace server exported one session per continued episode.
The 17 episodes with changed state had already made one or two successful tool calls that changed their session's tables.
Twelve had sent the email reply and five had moved one or two CRM customers to "Lost" before the checkpoint.
Each export differs from a freshly seeded session exactly where those calls changed it.
An email episode's export has one added row, the reply "RE: Task Update on Develop prototype for report generation", and every other email row equal to the seeded data.
A CRM episode that had updated customers
00000037and00000195exports both with status "Lost" where the seeded data has "Proposal", and no other cell differs.After the restore, all 131 continued episodes resumed rather than restarted:
At the end, the Workplace server and Simple Agent held no sessions.
The rewards are comparable to the uninterrupted run.
Over all 220 rollouts the mean was 0.295 (65 of 220), against 0.25 (10 of 40) uninterrupted.
By task, the email reply succeeded 44 of 44 times and the CRM status move 20 of 44 times, against 7 of 8 and 3 of 8.
The calendar rename succeeded once in 44 and the other two CRM tasks never, as in the baseline.
Of the 17 episodes caught after changing their state, 16 earned a reward of 1.
What is not covered
/verifyscores a trajectory by replaying its tool calls on a fresh environment, so the reward does not depend on the restored session.The restored state is shown instead by the second export and by the tool calls that ran on the restored sessions.
The typed
single_agent_turnrequest path did not run with Workplace Assistant.The model rarely solves three of the five tasks.
Compatibility
checkpoint:block set toenabled: true, behavior is unchanged. The hooks are only called by the checkpoint control routes.