feat(agent): add simple agent with context compaction - #2616
Conversation
d9960dc to
d842f49
Compare
|
/claude review |
|
SHIP WITH CARE Large, self-contained new agent ( One material finding, inline: the outbound body always carries Notes (author's call):
|
| else None | ||
| ), | ||
| } | ||
| ) |
There was a problem hiding this comment.
RISK — extra field breaks the compaction-disabled path.
WHAT BREAKS: required_prefix_token_ids is placed in the model_copy(update=...) dict unconditionally, even when context_session is None (compaction disabled). In pydantic v2, model_copy(update={...}) adds every update key to __pydantic_fields_set__, so ServerClient.request() — which serializes with model_dump(exclude_unset=True) (nemo_gym/server_utils.py:337) — keeps required_prefix_token_ids: null. When context_session is None the POST targets the standard /v1/responses handler (line 280-283), which validates into NeMoGymResponseCreateParamsNonStreaming (extra="forbid", openai_utils.py:499) that has no such field → 422 extra_forbidden on every model call, and raise_for_status aborts the rollout.
BLAST RADIUS: the shipped exemplar YAML sets context_history.enabled: true, so the default path (which routes to /v1/responses/context-compaction, a model that does declare the field) works. But the README advertises compaction as opt-in, and any config that leaves enabled at its False default hits the standard endpoint and hard-fails against a real vLLM server. It's not caught in tests because ServerClient.post is mocked and pydantic __eq__ ignores fields_set.
FIX: only inject the key when compaction is active, e.g. build the update dict conditionally so required_prefix_token_ids is absent when prepared_call is None. That keeps it out of fields_set and the standard endpoint accepts the body.
Signed-off-by: Ali Roshan Ghias <aroshanghias@nvidia.com>
Signed-off-by: Ali Roshan Ghias <aroshanghias@nvidia.com>
Signed-off-by: Ali Roshan Ghias <aroshanghias@nvidia.com>
Signed-off-by: Ali Roshan Ghias <aroshanghias@nvidia.com>
Signed-off-by: Ali Roshan Ghias <aroshanghias@nvidia.com>
Signed-off-by: Ali Roshan Ghias <aroshanghias@nvidia.com>
Signed-off-by: Ali Roshan Ghias <aroshanghias@nvidia.com>
Signed-off-by: Ali Roshan Ghias <aroshanghias@nvidia.com>
Signed-off-by: Ali Roshan Ghias <aroshanghias@nvidia.com>
Signed-off-by: Ali Roshan Ghias <aroshanghias@nvidia.com>
cee4364 to
ea02bc5
Compare
Summary
This PR adds a new opt-in
simple_agent_with_compactionResponses API agent for multi-turn semantic context compaction.Following reviewer feedback, the implementation is owned entirely by the new agent:
responses_api_agents/simple_agentis unchanged from the base branch;nemo_gymare unchanged;responses_api_agents/simple_agent_with_compaction/compaction;Users who select the existing
simple_agentsee no code-path or configuration change.Motivation
Multi-turn multimodal rollouts can repeatedly accumulate expensive context, particularly image observations and model reasoning blocks.
Dropping old request content is straightforward, but RL training also needs exact evidence about what each generation consumed and produced:
The new agent keeps semantic compaction separate from generation evidence. NeMo-RL can infer physical trace boundaries from exact prompt-token prefix relationships without retokenizing Gym output.
Design
Agent-owned semantic history
Each rollout owns an append-only semantic history containing model outputs and environment observations. Images are stored once in a content-addressed media arena and referenced by stable IDs. Compaction policies derive model-facing views without mutating the complete logical history.
Built-in policies:
identity: retains all semantic content;recency: independently supports image-group and reasoning-block retention.Policies return a view plan, which is materialized into a Responses API request. Omitted image runs may be replaced with explicit text markers.
Scheduling and rewrite boundaries
Two schedules are supported:
The controller compares each materialized request with the previously acknowledged request. A non-append-compatible view records a rewrite boundary and advances the context segment. Pending boundaries are retry-stable.
Exact generation evidence
The compaction session consumes generation-observed prompt IDs, sampled IDs, and logprobs, and carries exact-prefix requirements across append-compatible calls.
The vLLM adapter provides two explicit compaction capabilities:
/tokenizefor optional context-guard preflight;/v1/responses/context-compactionfor generation with an exact required token prefix.The prefix field is defined locally by the new agent and vLLM adapter rather than added to Gym's shared OpenAI schemas. Preflight tokenization is diagnostic only; generation evidence still comes from the generation operation.
Context guards
Optional guards can enforce limits on:
A turn-chunked schedule may close a nonempty chunk early and recompact before rejecting a request.
Response contract
The new agent returns versioned evidence records containing per-call token evidence, media occurrence order, policy-decision identity, lineage deltas, chunk records, rewrite-boundary records, and guard outcomes.
After resource verification, validation-only duplication is projected into a bounded transport envelope. When verification is explicitly skipped, the complete validation envelope is retained.
Example configuration
Compatibility
simple_agentimplementation and tests match the base branch.nemo_gymrequest schemas match the base branch.simple_agent_with_compaction.Validation
Focused validation ran on DFW with one GPU using the
rl-gym.63363213.sqshcontainer:simple_agent, and vLLM adapter cases passed;git diff --checkpasses;Supplemental downstream validation performed with the same compaction contract:
The deterministic environment and mocked-generation harness used for downstream validation are maintained outside this PR.
Non-goals
This PR does not:
simple_agent;Suggested review order
responses_api_agents/simple_agent_with_compaction/app.pyresponses_api_agents/simple_agent_with_compaction/compaction/history.pycompaction/policies.pyandcompaction/materialization.pycompaction/controller.pycompaction/session.pyresponses_api_models/vllm_model/app.py