agentcore-rl-toolkit 0.1.2__tar.gz → 0.1.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. agentcore_rl_toolkit-0.1.3/.gitignore +31 -0
  2. agentcore_rl_toolkit-0.1.2/README.md → agentcore_rl_toolkit-0.1.3/PKG-INFO +95 -24
  3. agentcore_rl_toolkit-0.1.2/PKG-INFO → agentcore_rl_toolkit-0.1.3/README.md +52 -52
  4. agentcore_rl_toolkit-0.1.3/docs/site/src/assets/houston.webp +0 -0
  5. agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/api/backends/slime/patches.md +68 -0
  6. agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/api/backends/slime/runner.md +150 -0
  7. agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/api/core/app.md +85 -0
  8. agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/api/core/client.md +412 -0
  9. agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/api/core/reward.md +45 -0
  10. agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/api/index.md +20 -0
  11. agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/examples/index.mdx +29 -0
  12. agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/examples/strands-appworld-agent.md +50 -0
  13. agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/examples/strands-math-agent.md +42 -0
  14. agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/examples/strands-migration-agent.md +57 -0
  15. agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/examples/strands-officebench-agent.md +72 -0
  16. agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/guides/agent-adaptation.mdx +183 -0
  17. agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/guides/overview.mdx +179 -0
  18. agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/guides/rllm-backend-setup.md +101 -0
  19. agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/guides/slime-backend-setup.md +128 -0
  20. agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/guides/verl-backend-setup.md +159 -0
  21. agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/index.mdx +116 -0
  22. agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/troubleshooting/rllm.md +14 -0
  23. agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/troubleshooting/slime.md +72 -0
  24. agentcore_rl_toolkit-0.1.3/docs/site/src/content/docs/troubleshooting/verl.md +14 -0
  25. agentcore_rl_toolkit-0.1.3/docs/site/src/content.config.ts +7 -0
  26. agentcore_rl_toolkit-0.1.3/docs/site/src/styles/custom.css +585 -0
  27. agentcore_rl_toolkit-0.1.3/pyproject.toml +112 -0
  28. {agentcore_rl_toolkit-0.1.2 → agentcore_rl_toolkit-0.1.3}/src/agentcore_rl_toolkit/app.py +20 -14
  29. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/__init__.py +0 -0
  30. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/SETUP.md +312 -0
  31. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/__init__.py +12 -0
  32. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/examples/math_agent/.wandb.env.example +23 -0
  33. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/examples/math_agent/config.yaml.example +21 -0
  34. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/examples/math_agent/eval.sh +175 -0
  35. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/examples/math_agent/train.py +22 -0
  36. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/examples/math_agent/train.sh +120 -0
  37. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/integration/__init__.py +0 -0
  38. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/integration/gateway.py +130 -0
  39. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/integration/rewards.py +102 -0
  40. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/integration/rollout.py +383 -0
  41. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/integration/traces.py +127 -0
  42. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/patches/__init__.py +0 -0
  43. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/patches/sglang_token_ids.py +696 -0
  44. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/patches/verify_sglang_token_ids.py +539 -0
  45. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/slime/runner.py +314 -0
  46. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/verl/__init__.py +44 -0
  47. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/verl/config/agentcore_grpo.yaml +71 -0
  48. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/verl/config.py +64 -0
  49. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/verl/dataset.py +26 -0
  50. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/verl/examples/math_agent/preprocess_gsm8k.py +58 -0
  51. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/verl/examples/math_agent/run_agentcore_grpo.sh +89 -0
  52. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/verl/llm_server.py +164 -0
  53. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/verl/loop_manager.py +556 -0
  54. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/verl/main.py +132 -0
  55. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/verl/scripts/install_megatron.sh +41 -0
  56. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/backends/verl/trainer.py +681 -0
  57. {agentcore_rl_toolkit-0.1.2 → agentcore_rl_toolkit-0.1.3}/src/agentcore_rl_toolkit/client.py +99 -34
  58. agentcore_rl_toolkit-0.1.3/src/agentcore_rl_toolkit/logging.py +58 -0
  59. agentcore_rl_toolkit-0.1.2/.gitignore +0 -23
  60. agentcore_rl_toolkit-0.1.2/pyproject.toml +0 -57
  61. {agentcore_rl_toolkit-0.1.2 → agentcore_rl_toolkit-0.1.3}/LICENSE +0 -0
  62. {agentcore_rl_toolkit-0.1.2 → agentcore_rl_toolkit-0.1.3}/NOTICE +0 -0
  63. {agentcore_rl_toolkit-0.1.2 → agentcore_rl_toolkit-0.1.3}/src/agentcore_rl_toolkit/__init__.py +0 -0
  64. {agentcore_rl_toolkit-0.1.2 → agentcore_rl_toolkit-0.1.3}/src/agentcore_rl_toolkit/frameworks/strands/__init__.py +0 -0
  65. {agentcore_rl_toolkit-0.1.2 → agentcore_rl_toolkit-0.1.3}/src/agentcore_rl_toolkit/frameworks/strands/vllm_model.py +0 -0
  66. {agentcore_rl_toolkit-0.1.2 → agentcore_rl_toolkit-0.1.3}/src/agentcore_rl_toolkit/reward_function.py +0 -0
@@ -0,0 +1,31 @@
1
+ # Virtual environments
2
+ .venv/
3
+ .venv-*/
4
+
5
+ # Python cache
6
+ __pycache__/
7
+ .ruff_cache/
8
+
9
+ # Build artifacts
10
+ *.egg-info/
11
+ dist/
12
+ build/
13
+
14
+ # Environment variables
15
+ .env
16
+ .wandb.env
17
+
18
+ # Local slime backend config (contains ARN/bucket; commit config.yaml.example only)
19
+ src/agentcore_rl_toolkit/backends/slime/examples/**/config.yaml
20
+
21
+ # Config files
22
+ config.toml
23
+
24
+ # Claude Code configuration: ignore everything by default,
25
+ # allowlist only skills meant to ship with the repo.
26
+ .claude/*
27
+ !.claude/skills/
28
+ .claude/skills/*
29
+ !.claude/skills/check-cloudwatch-session-logs/
30
+
31
+ .bedrock_agentcore.yaml
@@ -1,3 +1,46 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentcore-rl-toolkit
3
+ Version: 0.1.3
4
+ Summary: Toolkit for Seamlessly Enabling RL Training with Bedrock AgentCore.
5
+ Project-URL: Homepage, https://github.com/awslabs/agentcore-rl-toolkit
6
+ Author-email: Amazon Web Services - Labs <opensource@amazon.com>
7
+ License-Expression: Apache-2.0
8
+ License-File: LICENSE
9
+ License-File: NOTICE
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: License :: OSI Approved :: Apache Software License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Requires-Python: >=3.10
18
+ Requires-Dist: bedrock-agentcore-starter-toolkit>=0.2.0
19
+ Requires-Dist: bedrock-agentcore>=1.0.3
20
+ Requires-Dist: boto3>=1.40.55
21
+ Requires-Dist: python-dotenv>=1.0.0
22
+ Provides-Extra: dev
23
+ Requires-Dist: mypy>=1.0; extra == 'dev'
24
+ Requires-Dist: pre-commit>=3.0; extra == 'dev'
25
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
26
+ Requires-Dist: pytest>=7.0; extra == 'dev'
27
+ Provides-Extra: rllm
28
+ Requires-Dist: rllm; extra == 'rllm'
29
+ Provides-Extra: slime
30
+ Requires-Dist: rllm-model-gateway>=0.1.0; extra == 'slime'
31
+ Provides-Extra: verl
32
+ Requires-Dist: flash-attn==2.8.3; extra == 'verl'
33
+ Requires-Dist: numpy; extra == 'verl'
34
+ Requires-Dist: qwen-vl-utils; extra == 'verl'
35
+ Requires-Dist: ray; extra == 'verl'
36
+ Requires-Dist: rllm-model-gateway>=0.1.0; extra == 'verl'
37
+ Requires-Dist: torch>=2.10.0; extra == 'verl'
38
+ Requires-Dist: torchvision>=0.23.0; extra == 'verl'
39
+ Requires-Dist: transformers>=5.5.3; extra == 'verl'
40
+ Requires-Dist: verl==0.8.0; extra == 'verl'
41
+ Requires-Dist: vllm==0.21.0; extra == 'verl'
42
+ Description-Content-Type: text/markdown
43
+
1
44
 
2
45
  # AgentCore RL Toolkit (ART)
3
46
 
@@ -5,12 +48,12 @@ Toolkit to Seamlessly Enable RL Training on Any Agent with Bedrock AgentCore.
5
48
 
6
49
  ## Overview
7
50
 
8
- **AgentCore RL Toolkit (ART)** is an SDK that helps developers adapt their production LLM agents for online RL training with **AWS Bedrock AgentCore Runtime (ACR)**. It extends [bedrock-agentcore-sdk-python](https://github.com/aws/bedrock-agentcore-sdk-python/tree/main) so most of your production agent code can be directly reused.
51
+ **AgentCore RL Toolkit (ART)** is an SDK that helps developers adapt their production LLM agents for RL training with **AWS Bedrock AgentCore Runtime (ACR)**. It extends [bedrock-agentcore-sdk-python](https://github.com/aws/bedrock-agentcore-sdk-python/tree/main) so most of your production agent code can be directly reused.
9
52
 
10
53
  LLM agent rollouts are long-running — an agent may run for minutes or hours making tool calls. The toolkit manages this with an async-first design:
11
54
 
12
- - **Agent Adaptation** (`AgentCoreRLApp`, `vLLMModel`): Adapt your production agent for RL training inside ACR — the `@rollout_entrypoint` decorator runs your agent in the background with fire-and-forget semantics, collecting token-level data, computing rewards, and saving results to S3.
13
- - **Simplified Rollout Collection** (`RolloutClient`, `RolloutFuture`): Submit rollout requests and collect results asynchronously with a future-based API, built-in concurrency control, rate limiting, and S3 polling — for both training loops and batch evaluation.
55
+ - **Agent Adaptation** (`AgentCoreRLApp`, `@rollout_entrypoint`): A decorator swap turns your production agent into an async, fire-and-forget service — the agent runs in the background and saves results to S3. Return any JSON-serializable artifacts: rewards for RL training, evaluation metrics, conversation history, or custom data.
56
+ - **Rollout Collection** (`RolloutClient`, `RolloutFuture`): Submit requests and collect results asynchronously with a future-based API, built-in concurrency control, rate limiting, and S3 polling — for both training loops and batch evaluation.
14
57
 
15
58
  Both components use S3 as their data layer, but the complexity is fully abstracted — your code never reads from or writes to S3 directly.
16
59
 
@@ -40,8 +83,8 @@ While session routing is valuable for multi-turn production agents, RL rollouts
40
83
 
41
84
  ## Key Features
42
85
 
43
- - **Minimal code changes**: Adapt your production agent with a decorator swap (`@app.entrypoint` → `@app.rollout_entrypoint`) and model replacement — most of your agent code stays the same
44
- - **Token-accurate rollout data**: `vLLMModel` collects token IDs and logprobs directly from the inference server, avoiding retokenization issues that cause training instability
86
+ - **Minimal code changes**: Adapt your production agent with a decorator swap (`@app.entrypoint` → `@app.rollout_entrypoint`) — most of your agent code stays the same
87
+ - **No custom model wrappers**: Your agent uses standard framework models (e.g., `OpenAIModel`). Token capture for RL training is handled at the infrastructure layer, not in your agent code
45
88
  - **Async end-to-end**: Fire-and-forget server + future-based client — no long-lived TCP connections needed for long-running agent rollouts
46
89
  - **Simplified rollout collection**: `RolloutClient` manages concurrency, rate limiting, and S3 result polling out of the box for both training loops and batch evaluation
47
90
  - **Production parity**: Direct code reuse from production agents ensures training behavior matches real deployment
@@ -79,8 +122,8 @@ if __name__ == "__main__":
79
122
  Starting from a deployment-ready agent like above, here are the changes needed for RL training (see [`rl_app.py`](examples/strands_math_agent/rl_app.py) for full example):
80
123
  ```python
81
124
  from agentcore_rl_toolkit import AgentCoreRLApp
82
- from agentcore_rl_toolkit.frameworks.strands.vllm_model import vLLMModel
83
125
  from strands import Agent
126
+ from strands.models.openai import OpenAIModel
84
127
 
85
128
  app = AgentCoreRLApp()
86
129
  reward_fn = GSM8KReward() # user-defined reward function
@@ -89,24 +132,46 @@ reward_fn = GSM8KReward() # user-defined reward function
89
132
  def invoke_agent(payload: dict):
90
133
  base_url = payload["_rollout"]["base_url"]
91
134
  model_id = payload["_rollout"]["model_id"]
92
- model = vLLMModel(client_args={"api_key": "EMPTY", "base_url": base_url}, model_id=model_id)
135
+ model = OpenAIModel(client_args={"api_key": "EMPTY", "base_url": base_url}, model_id=model_id)
93
136
  agent = Agent(model=model, tools=[...], system_prompt="...")
94
137
 
95
138
  response = agent(payload.get("prompt"))
96
- rollout_data = model.get_token_data()
97
139
  rewards = reward_fn(response_text=response.message["content"][0]["text"], ground_truth=payload.get("answer"))
98
- return {"rollout_data": rollout_data, "rewards": rewards}
140
+ return {"rewards": rewards}
99
141
  ```
100
142
 
101
143
  **Key changes:**
102
144
  1. `BedrockAgentCoreApp` → `AgentCoreRLApp` (framework-agnostic)
103
- 2. `BedrockModel` → `vLLMModel` created inside the entrypoint with `base_url`/`model_id` from `_rollout` payload
145
+ 2. `BedrockModel` → `OpenAIModel` created inside the entrypoint with `base_url`/`model_id` from `_rollout` payload
104
146
  3. `@app.entrypoint` → `@app.rollout_entrypoint`
105
- 4. Use `model.get_token_data()` to collect token IDs directly (avoids retokenization)
106
- 5. Return `{"rollout_data": ..., "rewards": ...}` instead of text
147
+ 4. Return a dict instead of text (`rewards` key required for training)
148
+
149
+ > **Note:** The return value is flexible — any JSON-serializable dict works. This example returns rewards for training, but for evaluation you might return rewards, conversation history, or other artifacts. You can also persist raw data to S3 and run evaluation logic client-side.
107
150
 
108
151
  **Why create model and agent inside the entrypoint?** During RL training, the training engine can pass runtime configuration—such as inference server address, sampling parameters, and system prompt—via the `_rollout` payload, giving flexibility to accommodate different learning scenarios. This is safe because RL rollouts are single-invocation: the agent doesn't need persistent conversation history across requests, so there's no need to define model and agent as global variables.
109
152
 
153
+ ### Background: Token Capture for RL Training
154
+
155
+ > **Note:** This section is background knowledge — you don't need to configure any of this yourself. Token capture is managed by the training infrastructure.
156
+
157
+ RL for LLMs trains on token sequences, so trainers need the exact token IDs sampled by the model. But agents communicate via OpenAI-compatible APIs that return text, not tokens. Re-tokenizing that text back into IDs causes **retokenization drift** — the reconstructed IDs may differ from what the model actually generated, leading to off-policy updates that destabilize training. This drift has [three common sources](https://vllm.ai/blog/agent-lightning): (1) non-unique tokenization (e.g., `H`+`AVING` retokenizes as `HAV`+`ING`), (2) tool-call serialization changes (whitespace/formatting shifts during parsing and re-rendering), and (3) chat template misalignment across frameworks.
158
+
159
+ The solution is to capture token IDs directly from the inference server, avoiding retokenization entirely. [rllm-model-gateway](https://github.com/rllm-org/rllm/tree/main/rllm-model-gateway) does this as a transparent HTTP proxy between agents and the inference server:
160
+
161
+ ```
162
+ Agent ──► rllm-model-gateway ──► Inference Server (vLLM/SGLang)
163
+ │
164
+ └─► captures token IDs + logprobs, scoped by session
165
+ ```
166
+
167
+ The gateway intercepts OpenAI-compatible API responses and extracts token data directly from the server. Crucially, it scopes captured data by session ID — so when hundreds of concurrent agent sessions hit the same gateway, each rollout's token trace is correctly associated with its trajectory. Agents use a standard `OpenAIModel` and are completely unaware of the capture.
168
+
169
+ In practice, this is infrastructure managed by the training framework:
170
+ - **During training**: the training engine points `base_url` through the gateway automatically
171
+ - **During evaluation**: `base_url` points directly to any OpenAI-compatible endpoint (vLLM, SGLang, LiteLLM, etc.), or you can use `BedrockModel` via the Bedrock API — no gateway involved
172
+
173
+ The gateway is [available on PyPI](https://pypi.org/project/rllm-model-gateway/) (`pip install rllm-model-gateway`). See the [rllm-model-gateway repo](https://github.com/rllm-org/rllm/tree/main/rllm-model-gateway) for details.
174
+
110
175
  ## Client-Side: Invoking Agents and Collecting Results
111
176
 
112
177
  LLM agent rollouts are long-running and asynchronous — an agent may run for minutes or even hours as it reasons and makes tool calls. Both sides of this toolkit are designed around that constraint:
@@ -149,8 +214,8 @@ for f in futures:
149
214
 
150
215
  **How the future lifecycle works:**
151
216
  - **`client.invoke()`** sends the request to ACR and returns a `RolloutFuture` immediately — this means ACR has received the request and a background agent session is processing it.
152
- - **`future.result(timeout=...)`** blocks until the result appears in S3, polling with exponential backoff internally. It returns the complete rollout data (token IDs, rewards, etc.) once the agent finishes and writes to S3.
153
- - **Automatic session cleanup**: Once a result is fetched or a timeout is reached, the underlying ACR session is automatically cancelled — no manual cleanup needed.
217
+ - **`future.result(timeout=...)`** blocks until the result appears in S3, polling with exponential backoff internally. It returns the result (rewards, metrics, etc.) once the agent finishes and writes to S3.
218
+ - **Automatic session cleanup**: Once a result is fetched or a timeout is reached, the underlying ACR session is automatically cancelled to avoid wasteful idle time — no manual cleanup needed.
154
219
 
155
220
  ### Batch Evaluation (`run_batch()`)
156
221
 
@@ -207,10 +272,14 @@ The training architecture follows a **decoupled design** where agent rollouts an
207
272
  │ │ (e.g., veRL) │ │ (vLLM/SGLang) │ │
208
273
  │ └───────┬─────────────┘ └───────▲─────────────┘ │
209
274
  │ │ │ │
275
+ │ │ ┌───────┴─────────────┐ │
276
+ │ │ │ rllm-model-gateway │ │
277
+ │ │ │ (token capture) │ │
278
+ │ │ └───────▲─────────────┘ │
210
279
  └───────────────┼──────────────────────────┼─────────────────────┘
211
280
  │ 1. Submit N prompts │ ◄── ART Client-Side (1): RolloutClient
212
- │ to ACR │ 2. Model inference ◄── ART Agent-Side (2): vLLMModel
213
- ▼ │ calls from agents
281
+ │ to ACR │ 2. Model inference
282
+ ▼ │ via standard OpenAI API
214
283
  ┌────────────────────────────────────────────────────────────────┐
215
284
  │ AWS Bedrock AgentCore Runtime │
216
285
  │ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
@@ -219,28 +288,30 @@ The training architecture follows a **decoupled design** where agent rollouts an
219
288
  │ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ │
220
289
  │ │ │ │ │
221
290
  │ └──────────────┴───────────────────┘ │
222
- │ │ 3. Save rollouts + rewards │ ◄── ART Agent-Side (3): @rollout_entrypoint
291
+ │ │ 3. Save rewards to S3 │ ◄── ART Agent-Side (3): @rollout_entrypoint
223
292
  │ ▼ │
224
293
  │ ┌───────────────────┐ │
225
- │ │ S3 (rollouts) │ │
294
+ │ │ S3 (results) │ │
226
295
  │ └─────────┬─────────┘ │
227
296
  └─────────────────────────────┼──────────────────────────────────┘
228
297
  │ 4. Poll S3 HEAD for results ◄── ART Client-Side (4): RolloutFuture
229
298
  ▼
230
- Training Engine receives
231
- rollouts for policy update
299
+ Training Engine reads tokens
300
+ from gateway + rewards from S3
301
+ for policy update
232
302
  ```
233
303
 
234
304
  **Workflow:**
235
305
  1. **Prompt submission**: Training engine uses `RolloutClient` to submit N prompts to ACR — it injects rollout configs (`input_id`, `s3_bucket`, etc.) and handles rate limiting and concurrency, while ACR auto-scales N parallel agent sessions
236
- 2. **Agent execution**: Each agent session runs the `@rollout_entrypoint`, which launches the agent loop asynchronously (reporting `/ping` as busy) and calls the inference server via `vLLMModel` for model responses
237
- 3. **Rollout collection**: When the agent finishes, `@rollout_entrypoint` saves rollouts and rewards to S3 and reports `/ping` as idle so ACR can reclaim the session
238
- 4. **Policy update**: Training engine uses `RolloutFuture` to poll S3 for completed rollouts and updates the model
306
+ 2. **Agent execution**: Each agent session runs the `@rollout_entrypoint`, which launches the agent loop asynchronously (reporting `/ping` as busy) and calls the inference server via standard OpenAI-compatible API (through the gateway during training)
307
+ 3. **Result collection**: When the agent finishes, `@rollout_entrypoint` saves rewards to S3 and reports `/ping` as idle so ACR can reclaim the session
308
+ 4. **Policy update**: Training engine collects token data from the gateway and rewards from S3 to update the model
239
309
 
240
310
  This architecture enables parallel and highly efficient rollouts with secure execution during RL training. The decoupled design means training libraries only need the agent's container image to start training—agent code and dependencies stay completely separate from the training library.
241
311
 
242
312
  **Supported Training Libraries:**
243
- - To be announced.
313
+ - [rLLM](https://github.com/rllm-org/rllm) — supports multiple backends (veRL, Tinker, and more)
314
+ - [Math Agent](examples/strands_math_agent/): [Tinker](https://github.com/rllm-org/rllm/blob/main/examples/agentcore_math/train_agentcore_math_tinker.sh)
244
315
 
245
316
  ### Prepare Your Agent Container
246
317
 
@@ -1,31 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: agentcore-rl-toolkit
3
- Version: 0.1.2
4
- Summary: Toolkit for Seamlessly Enabling RL Training with Bedrock AgentCore.
5
- Project-URL: Homepage, https://github.com/awslabs/agentcore-rl-toolkit
6
- Author-email: Amazon Web Services - Labs <opensource@amazon.com>
7
- License-Expression: Apache-2.0
8
- License-File: LICENSE
9
- License-File: NOTICE
10
- Classifier: Development Status :: 3 - Alpha
11
- Classifier: License :: OSI Approved :: Apache Software License
12
- Classifier: Programming Language :: Python :: 3
13
- Classifier: Programming Language :: Python :: 3.10
14
- Classifier: Programming Language :: Python :: 3.11
15
- Classifier: Programming Language :: Python :: 3.12
16
- Classifier: Programming Language :: Python :: 3.13
17
- Requires-Python: >=3.10
18
- Requires-Dist: bedrock-agentcore-starter-toolkit>=0.2.0
19
- Requires-Dist: bedrock-agentcore>=1.0.3
20
- Requires-Dist: boto3>=1.40.55
21
- Requires-Dist: python-dotenv>=1.0.0
22
- Provides-Extra: dev
23
- Requires-Dist: mypy>=1.0; extra == 'dev'
24
- Requires-Dist: pre-commit>=3.0; extra == 'dev'
25
- Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
26
- Requires-Dist: pytest>=7.0; extra == 'dev'
27
- Description-Content-Type: text/markdown
28
-
29
1
 
30
2
  # AgentCore RL Toolkit (ART)
31
3
 
@@ -33,12 +5,12 @@ Toolkit to Seamlessly Enable RL Training on Any Agent with Bedrock AgentCore.
33
5
 
34
6
  ## Overview
35
7
 
36
- **AgentCore RL Toolkit (ART)** is an SDK that helps developers adapt their production LLM agents for online RL training with **AWS Bedrock AgentCore Runtime (ACR)**. It extends [bedrock-agentcore-sdk-python](https://github.com/aws/bedrock-agentcore-sdk-python/tree/main) so most of your production agent code can be directly reused.
8
+ **AgentCore RL Toolkit (ART)** is an SDK that helps developers adapt their production LLM agents for RL training with **AWS Bedrock AgentCore Runtime (ACR)**. It extends [bedrock-agentcore-sdk-python](https://github.com/aws/bedrock-agentcore-sdk-python/tree/main) so most of your production agent code can be directly reused.
37
9
 
38
10
  LLM agent rollouts are long-running — an agent may run for minutes or hours making tool calls. The toolkit manages this with an async-first design:
39
11
 
40
- - **Agent Adaptation** (`AgentCoreRLApp`, `vLLMModel`): Adapt your production agent for RL training inside ACR — the `@rollout_entrypoint` decorator runs your agent in the background with fire-and-forget semantics, collecting token-level data, computing rewards, and saving results to S3.
41
- - **Simplified Rollout Collection** (`RolloutClient`, `RolloutFuture`): Submit rollout requests and collect results asynchronously with a future-based API, built-in concurrency control, rate limiting, and S3 polling — for both training loops and batch evaluation.
12
+ - **Agent Adaptation** (`AgentCoreRLApp`, `@rollout_entrypoint`): A decorator swap turns your production agent into an async, fire-and-forget service — the agent runs in the background and saves results to S3. Return any JSON-serializable artifacts: rewards for RL training, evaluation metrics, conversation history, or custom data.
13
+ - **Rollout Collection** (`RolloutClient`, `RolloutFuture`): Submit requests and collect results asynchronously with a future-based API, built-in concurrency control, rate limiting, and S3 polling — for both training loops and batch evaluation.
42
14
 
43
15
  Both components use S3 as their data layer, but the complexity is fully abstracted — your code never reads from or writes to S3 directly.
44
16
 
@@ -68,8 +40,8 @@ While session routing is valuable for multi-turn production agents, RL rollouts
68
40
 
69
41
  ## Key Features
70
42
 
71
- - **Minimal code changes**: Adapt your production agent with a decorator swap (`@app.entrypoint` → `@app.rollout_entrypoint`) and model replacement — most of your agent code stays the same
72
- - **Token-accurate rollout data**: `vLLMModel` collects token IDs and logprobs directly from the inference server, avoiding retokenization issues that cause training instability
43
+ - **Minimal code changes**: Adapt your production agent with a decorator swap (`@app.entrypoint` → `@app.rollout_entrypoint`) — most of your agent code stays the same
44
+ - **No custom model wrappers**: Your agent uses standard framework models (e.g., `OpenAIModel`). Token capture for RL training is handled at the infrastructure layer, not in your agent code
73
45
  - **Async end-to-end**: Fire-and-forget server + future-based client — no long-lived TCP connections needed for long-running agent rollouts
74
46
  - **Simplified rollout collection**: `RolloutClient` manages concurrency, rate limiting, and S3 result polling out of the box for both training loops and batch evaluation
75
47
  - **Production parity**: Direct code reuse from production agents ensures training behavior matches real deployment
@@ -107,8 +79,8 @@ if __name__ == "__main__":
107
79
  Starting from a deployment-ready agent like above, here are the changes needed for RL training (see [`rl_app.py`](examples/strands_math_agent/rl_app.py) for full example):
108
80
  ```python
109
81
  from agentcore_rl_toolkit import AgentCoreRLApp
110
- from agentcore_rl_toolkit.frameworks.strands.vllm_model import vLLMModel
111
82
  from strands import Agent
83
+ from strands.models.openai import OpenAIModel
112
84
 
113
85
  app = AgentCoreRLApp()
114
86
  reward_fn = GSM8KReward() # user-defined reward function
@@ -117,24 +89,46 @@ reward_fn = GSM8KReward() # user-defined reward function
117
89
  def invoke_agent(payload: dict):
118
90
  base_url = payload["_rollout"]["base_url"]
119
91
  model_id = payload["_rollout"]["model_id"]
120
- model = vLLMModel(client_args={"api_key": "EMPTY", "base_url": base_url}, model_id=model_id)
92
+ model = OpenAIModel(client_args={"api_key": "EMPTY", "base_url": base_url}, model_id=model_id)
121
93
  agent = Agent(model=model, tools=[...], system_prompt="...")
122
94
 
123
95
  response = agent(payload.get("prompt"))
124
- rollout_data = model.get_token_data()
125
96
  rewards = reward_fn(response_text=response.message["content"][0]["text"], ground_truth=payload.get("answer"))
126
- return {"rollout_data": rollout_data, "rewards": rewards}
97
+ return {"rewards": rewards}
127
98
  ```
128
99
 
129
100
  **Key changes:**
130
101
  1. `BedrockAgentCoreApp` → `AgentCoreRLApp` (framework-agnostic)
131
- 2. `BedrockModel` → `vLLMModel` created inside the entrypoint with `base_url`/`model_id` from `_rollout` payload
102
+ 2. `BedrockModel` → `OpenAIModel` created inside the entrypoint with `base_url`/`model_id` from `_rollout` payload
132
103
  3. `@app.entrypoint` → `@app.rollout_entrypoint`
133
- 4. Use `model.get_token_data()` to collect token IDs directly (avoids retokenization)
134
- 5. Return `{"rollout_data": ..., "rewards": ...}` instead of text
104
+ 4. Return a dict instead of text (`rewards` key required for training)
105
+
106
+ > **Note:** The return value is flexible — any JSON-serializable dict works. This example returns rewards for training, but for evaluation you might return rewards, conversation history, or other artifacts. You can also persist raw data to S3 and run evaluation logic client-side.
135
107
 
136
108
  **Why create model and agent inside the entrypoint?** During RL training, the training engine can pass runtime configuration—such as inference server address, sampling parameters, and system prompt—via the `_rollout` payload, giving flexibility to accommodate different learning scenarios. This is safe because RL rollouts are single-invocation: the agent doesn't need persistent conversation history across requests, so there's no need to define model and agent as global variables.
137
109
 
110
+ ### Background: Token Capture for RL Training
111
+
112
+ > **Note:** This section is background knowledge — you don't need to configure any of this yourself. Token capture is managed by the training infrastructure.
113
+
114
+ RL for LLMs trains on token sequences, so trainers need the exact token IDs sampled by the model. But agents communicate via OpenAI-compatible APIs that return text, not tokens. Re-tokenizing that text back into IDs causes **retokenization drift** — the reconstructed IDs may differ from what the model actually generated, leading to off-policy updates that destabilize training. This drift has [three common sources](https://vllm.ai/blog/agent-lightning): (1) non-unique tokenization (e.g., `H`+`AVING` retokenizes as `HAV`+`ING`), (2) tool-call serialization changes (whitespace/formatting shifts during parsing and re-rendering), and (3) chat template misalignment across frameworks.
115
+
116
+ The solution is to capture token IDs directly from the inference server, avoiding retokenization entirely. [rllm-model-gateway](https://github.com/rllm-org/rllm/tree/main/rllm-model-gateway) does this as a transparent HTTP proxy between agents and the inference server:
117
+
118
+ ```
119
+ Agent ──► rllm-model-gateway ──► Inference Server (vLLM/SGLang)
120
+ │
121
+ └─► captures token IDs + logprobs, scoped by session
122
+ ```
123
+
124
+ The gateway intercepts OpenAI-compatible API responses and extracts token data directly from the server. Crucially, it scopes captured data by session ID — so when hundreds of concurrent agent sessions hit the same gateway, each rollout's token trace is correctly associated with its trajectory. Agents use a standard `OpenAIModel` and are completely unaware of the capture.
125
+
126
+ In practice, this is infrastructure managed by the training framework:
127
+ - **During training**: the training engine points `base_url` through the gateway automatically
128
+ - **During evaluation**: `base_url` points directly to any OpenAI-compatible endpoint (vLLM, SGLang, LiteLLM, etc.), or you can use `BedrockModel` via the Bedrock API — no gateway involved
129
+
130
+ The gateway is [available on PyPI](https://pypi.org/project/rllm-model-gateway/) (`pip install rllm-model-gateway`). See the [rllm-model-gateway repo](https://github.com/rllm-org/rllm/tree/main/rllm-model-gateway) for details.
131
+
138
132
  ## Client-Side: Invoking Agents and Collecting Results
139
133
 
140
134
  LLM agent rollouts are long-running and asynchronous — an agent may run for minutes or even hours as it reasons and makes tool calls. Both sides of this toolkit are designed around that constraint:
@@ -177,8 +171,8 @@ for f in futures:
177
171
 
178
172
  **How the future lifecycle works:**
179
173
  - **`client.invoke()`** sends the request to ACR and returns a `RolloutFuture` immediately — this means ACR has received the request and a background agent session is processing it.
180
- - **`future.result(timeout=...)`** blocks until the result appears in S3, polling with exponential backoff internally. It returns the complete rollout data (token IDs, rewards, etc.) once the agent finishes and writes to S3.
181
- - **Automatic session cleanup**: Once a result is fetched or a timeout is reached, the underlying ACR session is automatically cancelled — no manual cleanup needed.
174
+ - **`future.result(timeout=...)`** blocks until the result appears in S3, polling with exponential backoff internally. It returns the result (rewards, metrics, etc.) once the agent finishes and writes to S3.
175
+ - **Automatic session cleanup**: Once a result is fetched or a timeout is reached, the underlying ACR session is automatically cancelled to avoid wasteful idle time — no manual cleanup needed.
182
176
 
183
177
  ### Batch Evaluation (`run_batch()`)
184
178
 
@@ -235,10 +229,14 @@ The training architecture follows a **decoupled design** where agent rollouts an
235
229
  │ │ (e.g., veRL) │ │ (vLLM/SGLang) │ │
236
230
  │ └───────┬─────────────┘ └───────▲─────────────┘ │
237
231
  │ │ │ │
232
+ │ │ ┌───────┴─────────────┐ │
233
+ │ │ │ rllm-model-gateway │ │
234
+ │ │ │ (token capture) │ │
235
+ │ │ └───────▲─────────────┘ │
238
236
  └───────────────┼──────────────────────────┼─────────────────────┘
239
237
  │ 1. Submit N prompts │ ◄── ART Client-Side (1): RolloutClient
240
- │ to ACR │ 2. Model inference ◄── ART Agent-Side (2): vLLMModel
241
- ▼ │ calls from agents
238
+ │ to ACR │ 2. Model inference
239
+ ▼ │ via standard OpenAI API
242
240
  ┌────────────────────────────────────────────────────────────────┐
243
241
  │ AWS Bedrock AgentCore Runtime │
244
242
  │ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
@@ -247,28 +245,30 @@ The training architecture follows a **decoupled design** where agent rollouts an
247
245
  │ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ │
248
246
  │ │ │ │ │
249
247
  │ └──────────────┴───────────────────┘ │
250
- │ │ 3. Save rollouts + rewards │ ◄── ART Agent-Side (3): @rollout_entrypoint
248
+ │ │ 3. Save rewards to S3 │ ◄── ART Agent-Side (3): @rollout_entrypoint
251
249
  │ ▼ │
252
250
  │ ┌───────────────────┐ │
253
- │ │ S3 (rollouts) │ │
251
+ │ │ S3 (results) │ │
254
252
  │ └─────────┬─────────┘ │
255
253
  └─────────────────────────────┼──────────────────────────────────┘
256
254
  │ 4. Poll S3 HEAD for results ◄── ART Client-Side (4): RolloutFuture
257
255
  ▼
258
- Training Engine receives
259
- rollouts for policy update
256
+ Training Engine reads tokens
257
+ from gateway + rewards from S3
258
+ for policy update
260
259
  ```
261
260
 
262
261
  **Workflow:**
263
262
  1. **Prompt submission**: Training engine uses `RolloutClient` to submit N prompts to ACR — it injects rollout configs (`input_id`, `s3_bucket`, etc.) and handles rate limiting and concurrency, while ACR auto-scales N parallel agent sessions
264
- 2. **Agent execution**: Each agent session runs the `@rollout_entrypoint`, which launches the agent loop asynchronously (reporting `/ping` as busy) and calls the inference server via `vLLMModel` for model responses
265
- 3. **Rollout collection**: When the agent finishes, `@rollout_entrypoint` saves rollouts and rewards to S3 and reports `/ping` as idle so ACR can reclaim the session
266
- 4. **Policy update**: Training engine uses `RolloutFuture` to poll S3 for completed rollouts and updates the model
263
+ 2. **Agent execution**: Each agent session runs the `@rollout_entrypoint`, which launches the agent loop asynchronously (reporting `/ping` as busy) and calls the inference server via standard OpenAI-compatible API (through the gateway during training)
264
+ 3. **Result collection**: When the agent finishes, `@rollout_entrypoint` saves rewards to S3 and reports `/ping` as idle so ACR can reclaim the session
265
+ 4. **Policy update**: Training engine collects token data from the gateway and rewards from S3 to update the model
267
266
 
268
267
  This architecture enables parallel and highly efficient rollouts with secure execution during RL training. The decoupled design means training libraries only need the agent's container image to start training—agent code and dependencies stay completely separate from the training library.
269
268
 
270
269
  **Supported Training Libraries:**
271
- - To be announced.
270
+ - [rLLM](https://github.com/rllm-org/rllm) — supports multiple backends (veRL, Tinker, and more)
271
+ - [Math Agent](examples/strands_math_agent/): [Tinker](https://github.com/rllm-org/rllm/blob/main/examples/agentcore_math/train_agentcore_math_tinker.sh)
272
272
 
273
273
  ### Prepare Your Agent Container
274
274
 
@@ -0,0 +1,68 @@
1
+ ---
2
+ title: SGLang patches
3
+ description: Apply + verify the SGLang token-IDs patch used by the slime backend.
4
+ sidebar:
5
+ order: 4
6
+ ---
7
+
8
+
9
+ ## `agentcore_rl_toolkit.backends.slime.patches.sglang_token_ids`
10
+
11
+ Apply SGLang v0.5.9 patch to expose prompt/completion token IDs in chat completions.
12
+
13
+ SGLang's /v1/chat/completions endpoint does not include tokenized prompt or
14
+ completion IDs in the response. This patch adds four fields to the Pydantic
15
+ models and populates them from the engine's `output_ids` (always available)
16
+ and `adapted_request.input_ids`:
17
+
18
+ | Mode | Model | Field added |
19
+ |----------------|----------------------------------------------|----------------------|
20
+ | Non-streaming | ChatCompletionResponse | prompt_token_ids |
21
+ | Non-streaming | ChatCompletionResponseChoice | token_ids |
22
+ | Streaming | ChatCompletionStreamResponse (first chunk) | prompt_token_ids |
23
+ | Streaming | ChatCompletionResponseStreamChoice | token_ids (delta) |
24
+
25
+ Each Pydantic field is wrapped with a `@model_serializer` that drops the key
26
+ when None, so vanilla OpenAI clients see wire-identical responses.
27
+
28
+ For streaming, the patch handles three subtleties:
29
+
30
+ 1. `output_ids` is cumulative when `server_args.stream_output=False` (the
31
+ default); we slice past a per-index watermark to get the delta.
32
+ 2. The tool-call parser may yield 0, 1, or multiple chunks per engine yield,
33
+ so delta token IDs are buffered in `_pending_token_ids` and flushed onto
34
+ the first yielded chunk. If the parser yields nothing (partial JSON), the
35
+ IDs are re-buffered for the next iteration.
36
+ 3. When the detokenizer holds back text at word boundaries (empty `delta`),
37
+ or when the final token is EOS (empty `delta`), the buffer is preserved
38
+ and flushed onto the finish-reason chunk at stream end.
39
+
40
+ This enables rllm-model-gateway to capture exact RL-training trace data
41
+ without any gateway modifications and without requiring `logprobs=True`.
42
+
43
+ ## `apply_patch() -> bool`
44
+
45
+ Patch the installed SGLang package.
46
+
47
+ Returns True if either file was patched, False if both were already
48
+ patched, SGLang wasn't found, or patching failed.
49
+
50
+ ## `agentcore_rl_toolkit.backends.slime.patches.verify_sglang_token_ids`
51
+
52
+ Verify the SGLang v0.5.9 token_ids patch.
53
+
54
+ Launches a local SGLang server with the given model, issues greedy-decoded
55
+ chat completion requests in both streaming and non-streaming modes, and
56
+ checks that:
57
+
58
+ 1. Non-streaming responses expose prompt_token_ids (on the response) and
59
+ token_ids (per choice), and decoding token_ids matches the content.
60
+ 2. Streaming responses expose prompt_token_ids on the first chunk and
61
+ token_ids on content chunks, and decoding the concatenation matches
62
+ the concatenated deltas.
63
+ 3. Under greedy decoding, the prompt and completion token sequences are
64
+ identical between streaming and non-streaming modes.
65
+ 4. Streaming with tools active yields the same completion token sequence
66
+ as streaming without tools, validating the _pending_token_ids buffering.
67
+
68
+ ## `main(argv: Optional[list[str]] = None) -> int`