Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
1117 commits
Select commit Hold shift + click to select a range
9e8945b
close pty session
bxyu-nvidia Aug 27, 2026
5d54282
fix temp_file write
bxyu-nvidia Aug 27, 2026
e870676
dont print huge trace on canceled error
bxyu-nvidia Aug 27, 2026
edbcab8
omit detach
bxyu-nvidia Aug 27, 2026
64384c1
remove custom
bxyu-nvidia Aug 27, 2026
77cf63f
remove pty gap assertion
bxyu-nvidia Aug 27, 2026
3b6e742
add back detach
bxyu-nvidia Aug 27, 2026
d38b166
async scheduling!
bxyu-nvidia Aug 27, 2026
df47611
try add resource patch
bxyu-nvidia Aug 27, 2026
79333c8
no async XD
bxyu-nvidia Aug 27, 2026
3acfac7
add back custom
bxyu-nvidia Aug 27, 2026
17e2924
try add pty back to opencode
bxyu-nvidia Aug 27, 2026
eec6111
fix tests
bxyu-nvidia Aug 27, 2026
92a5fb0
fix seed session request
bxyu-nvidia Aug 27, 2026
3cabae9
remove not implemented error
bxyu-nvidia Aug 27, 2026
58b2ccb
reattach to session
bxyu-nvidia Aug 27, 2026
fbb9de2
detach from pty
bxyu-nvidia Aug 27, 2026
a9be9ed
skip detach again
bxyu-nvidia Aug 27, 2026
baa19f5
remove custom
bxyu-nvidia Aug 27, 2026
86e1fce
unset reservation on cleanup
bxyu-nvidia Aug 28, 2026
2fd1d3e
actually return session id
bxyu-nvidia Aug 28, 2026
e8f3229
fix seed session
bxyu-nvidia Aug 28, 2026
58895c5
fix submit dir
bxyu-nvidia Aug 28, 2026
c73826b
reduce default opencode resources used
bxyu-nvidia Aug 28, 2026
84c8d56
fix copy issue
bxyu-nvidia Aug 28, 2026
6eba357
log lower bound
bxyu-nvidia Aug 28, 2026
f9232bc
Retry PTY takeover attach when execd's eviction times out
hemildesai Aug 28, 2026
0ccf12a
Merge branch 'main' of https://github.com/NVIDIA-NeMo/Gym into bxyu/h…
bxyu-nvidia Aug 28, 2026
5250956
Merge branch 'hemild/pty-takeover-retry' of https://github.com/NVIDIA…
bxyu-nvidia Aug 28, 2026
55d1e66
dont use login shell for main job
bxyu-nvidia Aug 28, 2026
9f62ee1
Detach the PTY baton instead of dangling it, and heartbeat the sockets
hemildesai Aug 28, 2026
c084c44
move all to -c
bxyu-nvidia Aug 28, 2026
e2f4de3
swwap swebench to pty; remove unnecessary opencode conda activate
bxyu-nvidia Aug 28, 2026
2e3d36a
Merge branch 'main' of https://github.com/NVIDIA-NeMo/Gym into bxyu/h…
bxyu-nvidia Aug 28, 2026
7f25583
clean
bxyu-nvidia Aug 28, 2026
e7eb2b6
fix opencode finished
bxyu-nvidia Aug 28, 2026
72e0522
try fix test.sh
bxyu-nvidia Aug 28, 2026
ad08ac6
Merge branch 'main' of https://github.com/NVIDIA-NeMo/Gym into bxyu/h…
bxyu-nvidia Aug 28, 2026
aa1ddba
Merge branch 'hemild/pty-takeover-retry' of https://github.com/NVIDIA…
bxyu-nvidia Aug 28, 2026
19478c4
clean
bxyu-nvidia Aug 28, 2026
ca1a481
fix tests
bxyu-nvidia Aug 28, 2026
f2d84ce
Merge branch 'main' of https://github.com/NVIDIA-NeMo/Gym into bxyu/h…
bxyu-nvidia Aug 28, 2026
8740c7b
clean
bxyu-nvidia Aug 28, 2026
5efc3b8
fix nested import
bxyu-nvidia Aug 28, 2026
8640a15
Merge branch 'main' of https://github.com/NVIDIA-NeMo/Gym into bxyu/h…
bxyu-nvidia Aug 28, 2026
a09e6a8
perf(model-server): serialize non-streaming dispatch results with orjson
ananthsub Aug 28, 2026
f7246b4
perf(server): parse HTTP with httptools instead of pure-Python h11
ananthsub Aug 28, 2026
298fd98
docs(model-server): clarify orjson serialization comments
ananthsub Aug 29, 2026
5955b0c
docs(server): clarify httptools selection comments
ananthsub Aug 29, 2026
ce5cc85
test(model-server): cover orjson dispatch serialization
ananthsub Aug 29, 2026
e3dcdc5
Merge branch 'ananthsub/model-server-orjson-dispatch' of https://gith…
bxyu-nvidia Aug 29, 2026
eef5e18
Merge branch 'ananthsub/uvicorn-httptools' of https://github.com/anan…
bxyu-nvidia Aug 29, 2026
b48f0b6
start terminus2 sandboxed agent
bxyu-nvidia Aug 30, 2026
c8fbc8d
try start app
bxyu-nvidia Aug 30, 2026
de2dacc
clean
bxyu-nvidia Aug 30, 2026
54a42bb
add config
bxyu-nvidia Aug 30, 2026
2d62293
add tests
bxyu-nvidia Aug 30, 2026
70ec5e5
add terminus path
bxyu-nvidia Aug 30, 2026
03f549b
swap tb2.1 opencode with terminus
bxyu-nvidia Aug 30, 2026
fce7144
strict equals
bxyu-nvidia Aug 30, 2026
f047360
add sandbox_utils script
bxyu-nvidia Aug 30, 2026
633a048
cleanup
bxyu-nvidia Aug 30, 2026
34044c0
try openai prefix
bxyu-nvidia Aug 30, 2026
04a7d92
fix errors
bxyu-nvidia Aug 30, 2026
1e18520
add sandbox utils
bxyu-nvidia Aug 30, 2026
1f11ff1
use dummy api key
bxyu-nvidia Aug 30, 2026
af25dde
use gym async openai client; export all messages
bxyu-nvidia Aug 31, 2026
7d1d69a
increase pty size
bxyu-nvidia Aug 31, 2026
8cf8ad4
set warning logger
bxyu-nvidia Aug 31, 2026
362cb38
max turns null; model context limit 262k
bxyu-nvidia Aug 31, 2026
939e34a
increase workers idk
bxyu-nvidia Aug 31, 2026
d8e9ef7
Merge branch 'main' of https://github.com/NVIDIA-NeMo/Gym into bxyu/h…
bxyu-nvidia Aug 31, 2026
edcf9b6
require pty session; fix session id
bxyu-nvidia Aug 31, 2026
bd91697
fix logger set
bxyu-nvidia Aug 31, 2026
72567b5
output terminus2 completed
bxyu-nvidia Aug 31, 2026
43bbf73
fix(pty): retry on WS_CLOSE_POLICY_VIOLATION after a reattach
hemildesai Aug 31, 2026
718fbdc
clean
bxyu-nvidia Aug 31, 2026
06270a1
back to 4 workers
bxyu-nvidia Aug 31, 2026
a882cac
fix(terminal_bench_2_1): detach old PTY session before reattach at ve…
hemildesai Aug 31, 2026
83d1cdc
Merge branch 'main' of https://github.com/NVIDIA-NeMo/Gym into bxyu/h…
bxyu-nvidia Aug 31, 2026
dfde008
detach opencode
bxyu-nvidia Aug 31, 2026
a6f6941
always print on exception
bxyu-nvidia Aug 31, 2026
5a3be51
try bump up policy model num workers
bxyu-nvidia Aug 31, 2026
de2ec3d
try except sandbox pty reattach
bxyu-nvidia Aug 31, 2026
6c9322f
print tmux error
bxyu-nvidia Aug 31, 2026
24292cd
fix(pty): retry on ServerDisconnectedError during WS upgrade
hemildesai Aug 31, 2026
1899749
no num workers
bxyu-nvidia Aug 31, 2026
33a31d6
no num workers
bxyu-nvidia Aug 31, 2026
cf3846e
print result too
bxyu-nvidia Aug 31, 2026
010893f
fork on pty session
bxyu-nvidia Aug 31, 2026
034ca73
print failed commands
bxyu-nvidia Aug 31, 2026
7883992
extend tool install timeout sec for setup; print errors during setup
bxyu-nvidia Aug 31, 2026
9d3feb8
try revert responses
bxyu-nvidia Aug 31, 2026
415c1e6
Revert "extend tool install timeout sec for setup; print errors durin…
bxyu-nvidia Aug 31, 2026
2b4c138
clean
bxyu-nvidia Aug 31, 2026
3f28a3d
see how many are not through pty
bxyu-nvidia Aug 31, 2026
7a4c33b
install tmux manually
bxyu-nvidia Aug 31, 2026
39413e2
apt update
bxyu-nvidia Aug 31, 2026
adb1169
use same pty session
bxyu-nvidia Aug 31, 2026
e00994b
back to 4 workers
bxyu-nvidia Aug 31, 2026
38f2de7
print to stderr
bxyu-nvidia Aug 31, 2026
54c1ca5
extend tmux installation time
bxyu-nvidia Aug 31, 2026
7f27bea
try reduce pty size
bxyu-nvidia Aug 31, 2026
0b087cf
Revert "try reduce pty size"
bxyu-nvidia Aug 31, 2026
cb191a3
revert pty size
bxyu-nvidia Aug 31, 2026
d73df62
Merge branch 'main' of https://github.com/NVIDIA-NeMo/Gym into bxyu/h…
bxyu-nvidia Aug 31, 2026
d3c841f
clean
bxyu-nvidia Aug 31, 2026
766a184
move override to sandbox utils
bxyu-nvidia Aug 31, 2026
0e7fa2c
add sandbox utils and policy model override to every bench
bxyu-nvidia Aug 31, 2026
02e9dc5
add comment
bxyu-nvidia Aug 31, 2026
119ac9a
try add gym model params
bxyu-nvidia Aug 31, 2026
9d7c136
add instructions for mounting tmux binary
bxyu-nvidia Aug 31, 2026
18216ea
parameterize remote_tmux_binary_path
bxyu-nvidia Aug 31, 2026
149a58d
add tmux binary mount to sandbox utils config
bxyu-nvidia Aug 31, 2026
68a9ead
fix
bxyu-nvidia Aug 31, 2026
9fc5f67
clean inherit
bxyu-nvidia Aug 31, 2026
814b306
fix binary
bxyu-nvidia Aug 31, 2026
30c5712
fix(pty): retry 1008 on initial attach socket when takeover was reque…
hemildesai Aug 31, 2026
9de4663
fix(pty): strip echoed input, prompts, and marker lines from exec stdout
hemildesai Aug 31, 2026
68de905
refactor(pty): detach own stale attachment inside attach_pty takeover
hemildesai Aug 31, 2026
e266c5f
remove duplicate title
bxyu-nvidia Aug 31, 2026
9227c2b
dont detach idk
bxyu-nvidia Aug 31, 2026
28b74d0
chmod tmux
bxyu-nvidia Aug 31, 2026
d537f1f
docs(pty): plain-language comments for the attach-refusal race
hemildesai Sep 1, 2026
1ee1891
Merge branch 'hemild/fix-pty-policy-violation-retry' of https://githu…
bxyu-nvidia Sep 1, 2026
6b03b50
raise on non pty
bxyu-nvidia Sep 1, 2026
ba21da3
try exec stop
bxyu-nvidia Sep 1, 2026
494e967
print new-session creation
bxyu-nvidia Sep 1, 2026
d91e49e
try tweak scheduling args
bxyu-nvidia Sep 1, 2026
fee5f9e
revert
bxyu-nvidia Sep 1, 2026
8014f92
try no detached at all
bxyu-nvidia Sep 1, 2026
91204cd
try centralize to gym clientsession
bxyu-nvidia Sep 1, 2026
cd4a253
Revert "Merge branch 'hemild/fix-pty-policy-violation-retry' of https…
bxyu-nvidia Sep 1, 2026
2349f73
Merge branch 'main' of https://github.com/NVIDIA-NeMo/Gym into bxyu/h…
bxyu-nvidia Sep 1, 2026
f550974
clean
bxyu-nvidia Sep 1, 2026
15d5e54
remove exception
bxyu-nvidia Sep 1, 2026
b2b58b6
dont close client
bxyu-nvidia Sep 1, 2026
67a8b40
Merge branch 'main' of https://github.com/NVIDIA-NeMo/Gym into bxyu/h…
bxyu-nvidia Sep 1, 2026
df5a27d
release pty session
bxyu-nvidia Sep 1, 2026
0fb7ac7
detach in seed session
bxyu-nvidia Sep 1, 2026
e0eaee3
print separate errors for closed
bxyu-nvidia Sep 1, 2026
ffff9c8
try opencode detach
bxyu-nvidia Sep 1, 2026
b12fce7
idk i let codex do something
bxyu-nvidia Sep 1, 2026
86b2231
feat(pty): report sandbox OOM kills instead of bare websocket close c…
hemildesai Sep 1, 2026
e5ef450
Merge branch 'hemild/pty-oom-diagnosis' of https://github.com/NVIDIA-…
bxyu-nvidia Sep 1, 2026
7e12c46
also except ClientConnectionError
bxyu-nvidia Sep 1, 2026
b80a718
try filter terminate failed logs
bxyu-nvidia Sep 1, 2026
63d274c
Revert "idk i let codex do something"
bxyu-nvidia Sep 1, 2026
eca0846
back to main
bxyu-nvidia Sep 1, 2026
881db9f
dont release
bxyu-nvidia Sep 1, 2026
dcba202
fully clean client close
bxyu-nvidia Sep 1, 2026
8943ac6
gate download behind export result
bxyu-nvidia Sep 1, 2026
585c559
remove clientconnectorerror
bxyu-nvidia Sep 1, 2026
b37be9e
remove pty
bxyu-nvidia Sep 1, 2026
0aff5eb
print session list result
bxyu-nvidia Sep 1, 2026
1c58f1a
try except tests run
bxyu-nvidia Sep 1, 2026
c0a6e9d
only try download if eval result is not none
bxyu-nvidia Sep 1, 2026
dbd76fb
policy model num workers 16
bxyu-nvidia Sep 1, 2026
6c41a38
clean terminus 2 of pty
bxyu-nvidia Sep 1, 2026
827cbda
start pipe env patches
bxyu-nvidia Sep 1, 2026
7c52572
try except stop
bxyu-nvidia Sep 1, 2026
327a65a
revert swe bench pty
bxyu-nvidia Sep 1, 2026
53086d9
try fix swe path
bxyu-nvidia Sep 1, 2026
17c9641
remove num workers
bxyu-nvidia Sep 1, 2026
c5d4267
wrap folder upload in exception handling too
bxyu-nvidia Sep 1, 2026
c1159ac
add back num workers
bxyu-nvidia Sep 1, 2026
b54b8d5
try except terminus 2 fail
bxyu-nvidia Sep 1, 2026
6c3b874
reduce background poll interval 30 -> 5
bxyu-nvidia Sep 1, 2026
2ed1e95
use 16 opencode workers
bxyu-nvidia Sep 1, 2026
479de74
revert background poll interval s
bxyu-nvidia Sep 1, 2026
81724d3
fix(pty): reattach() sockets are takeovers — retry a refused one
hemildesai Sep 1, 2026
e7361cb
feat(pty): report sandbox OOM kills instead of bare websocket close c…
hemildesai Sep 1, 2026
6d7ee0d
feat(pty): report a dead sandbox when takeover retries are exhausted
hemildesai Sep 1, 2026
3e2b0f3
fix(pty): name any sandbox death behind an unexpected close, not just…
hemildesai Sep 1, 2026
38766f9
try increase bash default timeout
bxyu-nvidia Sep 1, 2026
9bb3297
back to 4 workers
bxyu-nvidia Sep 1, 2026
595d653
Merge branch 'main' of https://github.com/NVIDIA-NeMo/Gym into bxyu/h…
bxyu-nvidia Sep 1, 2026
b63f74f
Merge branch 'hemild/fix-pty-policy-violation-retry' of https://githu…
bxyu-nvidia Sep 1, 2026
6280b61
revert to use pty again
bxyu-nvidia Sep 1, 2026
c6e48f9
detach true for opencode
bxyu-nvidia Sep 1, 2026
941d9b4
min timeout is 5s
bxyu-nvidia Sep 1, 2026
f931469
fix await
bxyu-nvidia Sep 1, 2026
b2033e5
remove
bxyu-nvidia Sep 2, 2026
1fb0438
try except pty session reattach failure
bxyu-nvidia Sep 2, 2026
4447e22
feat: add vllm router patch for decode imbalance
sdevare-nv Sep 2, 2026
3638788
feat: update scripts
sdevare-nv Sep 2, 2026
f2e326f
feat: update readme
sdevare-nv Sep 2, 2026
874ba7c
Revert "try except pty session reattach failure"
bxyu-nvidia Sep 2, 2026
e975658
Revert "detach true for opencode"
bxyu-nvidia Sep 2, 2026
d8947e0
Revert "revert to use pty again"
bxyu-nvidia Sep 2, 2026
10ddabf
Revert "try increase bash default timeout"
bxyu-nvidia Sep 2, 2026
0bf1622
cleanup pty changes
bxyu-nvidia Sep 2, 2026
958e507
cleanup
sdevare-nv Sep 2, 2026
01be13e
Merge branch 'sdd/vllm-router-cache-imbalance' of https://github.com/…
bxyu-nvidia Sep 2, 2026
6d9728b
clean
bxyu-nvidia Sep 2, 2026
011b8ee
c;eam
bxyu-nvidia Sep 2, 2026
d20d58d
clean
bxyu-nvidia Sep 2, 2026
e8c3dbd
swap order
bxyu-nvidia Sep 2, 2026
0ba2e8a
clean
bxyu-nvidia Sep 2, 2026
5b639f4
add comment
bxyu-nvidia Sep 2, 2026
d3d7afc
fix missing slash
bxyu-nvidia Sep 2, 2026
e7082df
add super mtp config
bxyu-nvidia Sep 2, 2026
7733aa0
try mtp in shared
bxyu-nvidia Sep 2, 2026
5666ace
try pass balance abs and rel thresholds
bxyu-nvidia Sep 2, 2026
b443332
use 4
bxyu-nvidia Sep 2, 2026
30c32c9
try power of 2
bxyu-nvidia Sep 2, 2026
31d9d1c
back to cache aware
bxyu-nvidia Sep 2, 2026
bab8acd
use 1 repeat
bxyu-nvidia Sep 2, 2026
500b531
back to 8 repeats
bxyu-nvidia Sep 2, 2026
87ce067
Merge branch 'main' of https://github.com/NVIDIA-NeMo/Gym into bxyu/h…
bxyu-nvidia Sep 2, 2026
7f42ebb
Merge branch 'main' of https://github.com/NVIDIA-NeMo/Gym into bxyu/h…
bxyu-nvidia Sep 2, 2026
06af043
downlevel max concurrency
bxyu-nvidia Sep 2, 2026
77b5191
try log metrics
bxyu-nvidia Sep 2, 2026
e96e54e
use 128 max concurrency
bxyu-nvidia Sep 2, 2026
38a8a81
allow null
bxyu-nvidia Sep 2, 2026
276cd09
set max concurrency
bxyu-nvidia Sep 2, 2026
7c94a0b
actually limit :skull:
bxyu-nvidia Sep 2, 2026
601fdfb
log more metrics
bxyu-nvidia Sep 2, 2026
162bb58
unset max concurrency
bxyu-nvidia Sep 3, 2026
8a62739
feat(swebench,opencode): set EXECD_API_GRACE_SHUTDOWN=50ms in the san…
hemildesai Sep 3, 2026
cd5b36f
fix trajectory duplication
bxyu-nvidia Sep 3, 2026
bee5de7
dont stop tmux
bxyu-nvidia Sep 3, 2026
7e1892a
apt get update
bxyu-nvidia Sep 3, 2026
8f77769
remove semaphore logic
bxyu-nvidia Sep 3, 2026
d868d76
dont duplicate model output
bxyu-nvidia Sep 3, 2026
e13dbe4
try with cancel middleware
bxyu-nvidia Sep 3, 2026
4d783cb
add 10min timeout to match litellm
bxyu-nvidia Sep 3, 2026
c121026
fix test
bxyu-nvidia Sep 3, 2026
9df8376
log number of calls exceeding 10mins
bxyu-nvidia Sep 3, 2026
fb02c22
log num compactions
bxyu-nvidia Sep 3, 2026
43a9792
clarity litellm timeout set
bxyu-nvidia Sep 3, 2026
aaf39fa
swap back to asgi
bxyu-nvidia Sep 3, 2026
f9394a2
print mod 100
bxyu-nvidia Sep 3, 2026
a847579
clean
bxyu-nvidia Sep 3, 2026
0e93b5b
Merge branch 'main' of https://github.com/NVIDIA-NeMo/Gym into bxyu/h…
bxyu-nvidia Sep 3, 2026
11a201c
Merge branch 'main' of https://github.com/NVIDIA-NeMo/Gym into bxyu/h…
bxyu-nvidia Sep 3, 2026
1419c72
bump deepswe repeats to 10
bxyu-nvidia Sep 3, 2026
5b9de08
Merge branch 'hemild/opensandbox-execd-grace' of https://github.com/N…
bxyu-nvidia Sep 3, 2026
906bae1
add execd
bxyu-nvidia Sep 3, 2026
32a8e7e
use 10 retries
bxyu-nvidia Sep 3, 2026
94a29d8
log error
bxyu-nvidia Sep 3, 2026
363d14b
try no keepalive and socket factory
bxyu-nvidia Sep 4, 2026
ea3c3b7
raise context length error on
bxyu-nvidia Sep 4, 2026
e342207
remove counting tokens hack
bxyu-nvidia Sep 4, 2026
9913993
fix condition
bxyu-nvidia Sep 4, 2026
ad163c5
dont print
bxyu-nvidia Sep 4, 2026
e7ec9f8
try fix client disconnect counter
bxyu-nvidia Sep 4, 2026
9fe865a
add error analysis script
bxyu-nvidia Sep 4, 2026
b01bd9a
clean
bxyu-nvidia Sep 4, 2026
7898ea8
add back clientsession args
bxyu-nvidia Sep 4, 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
2 changes: 1 addition & 1 deletion benchmarks/deepswe/opencode.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ opencode_sandboxed_agent_deepswe:
type: benchmark
jsonl_fpath: benchmarks/deepswe/data/deepswe_benchmark.jsonl
prepare_script: benchmarks/deepswe/prepare.py
num_repeats: 5
num_repeats: 10
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/bin/bash

GYM_MODEL_PARAMS=(
"++policy_model.responses_api_models.vllm_model.sampling_overrides.temperature=1.0"
"++policy_model.responses_api_models.vllm_model.sampling_overrides.top_p=0.95"
)

# @bxyu-nvidia: `--skip-mm-profiling` Is needed to get Super VL checkpoint working, even with text benchmarks
VLLM_COMMON_ARGS=(
--trust-remote-code
--disable-uvicorn-access-log
--gpu-memory-utilization 0.9
--distributed-executor-backend mp
--data-parallel-backend mp
--enable-auto-tool-choice
--tool-call-parser qwen3_coder
--reasoning-parser nemotron_v3
--enable-chunked-prefill
--enable-prefix-caching
--max-model-len 262144
--kv-cache-dtype fp8
--no-disable-hybrid-kv-cache-manager
--block-size 128
--mamba-cache-mode align
--mamba-ssm-cache-dtype float32
--model-loader-extra-config '{"enable_multithread_load": true, "num_threads": 96}'
--enable-expert-parallel
--skip-mm-profiling
--data-parallel-size 1
--api-server-count 1
--speculative-config '{"method":"mtp","num_speculative_tokens":5}'
)
VLLM_PREFILL_ARGS=(
--kv-transfer-config '{"kv_connector":"NixlConnector","kv_role":"kv_producer","kv_load_failure_policy":"fail"}'
--max-num-batched-tokens 135680
--max-num-seqs 1024
--data-parallel-size-local 1
--tensor-parallel-size 4
)
VLLM_DECODE_ARGS=(
--kv-transfer-config '{"kv_connector":"NixlConnector","kv_role":"kv_consumer","kv_load_failure_policy":"fail"}'
--compilation-config '{"cudagraph_mode":"FULL_DECODE_ONLY"}'
--max-num-batched-tokens 33920
--max-num-seqs 1024
--data-parallel-size-local 1
--tensor-parallel-size 4
)
Original file line number Diff line number Diff line change
Expand Up @@ -238,3 +238,5 @@ Command failures return `SandboxExecResult` with the command's exit code. If Ope
The provider's `create.image_pull_policy` defaults to `IfNotPresent`. Valid values are `Always`, `IfNotPresent`, and `Never`. The resolved policy is written into OpenSandbox create extensions as both `imagePullPolicy` and `opensandbox.extensions.image-pull-policy` unless those keys are already present in `provider_options.extensions`.

Create retries handle transient allocation, connection, image pull, and server-side errors. Command retries are controlled separately by `operations.command_retries`.

execd, the exec daemon inside each sandbox, holds every command response open for `EXECD_API_GRACE_SHUTDOWN` (default 1s) after the command's last event, which is fixed latency on each command and on the readiness probe. Set it in the sandbox spec's `env` to shorten it; the shipped SWE-bench and OpenCode configs use `50ms`, and the provider's `operations.background_poll_initial_s` (0.5) is sized to that.
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,9 @@ sandbox:
# Poll interval backs off from initial to interval.
# @bxyu-nvidia: Too frequent of a poll interval can quickly reduce server performance.
# e.g. on SWE Bench Verified 500 samples with 3 repeats = 1500 concurrent samples, we would do polling every `background_poll_interval_s` seconds
background_poll_initial_s: 1.0
# Assumes a short execd response grace (EXECD_API_GRACE_SHUTDOWN in the sandbox env; the
# shipped swebench and opencode configs set 50ms).
background_poll_initial_s: 0.5
background_poll_interval_s: 30.0
# Per-request budget for status polls, which are small idempotent GETs:
# without their own short budget, each poll against an unreachable
Expand Down
18 changes: 15 additions & 3 deletions nemo_gym/server_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -746,13 +746,18 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:

received_messages: asyncio.Queue[Message] = asyncio.Queue()
client_disconnected = asyncio.Event()
response_complete = asyncio.Event()

async def receive_message() -> Message:
return await received_messages.get()

async def send_message(message: Message) -> None:
if not client_disconnected.is_set():
await send(message)
if client_disconnected.is_set():
return

await send(message)
if message["type"] == "http.response.body" and not message.get("more_body", False):
response_complete.set()

# The listener is the sole reader of the original ASGI receive channel.
# Forwarding request messages keeps the body available to the app while
Expand All @@ -768,10 +773,17 @@ async def run_app() -> None:
async def listen_for_disconnect() -> None:
while True:
message = await receive()
await received_messages.put(message)
if message["type"] != "http.disconnect":
await received_messages.put(message)
continue

# Uvicorn returns http.disconnect from receive() once the response is complete,
# even if the peer did not disconnect early. Only cancel requests whose response
# has not finished being sent.
if response_complete.is_set():
return

await received_messages.put(message)
client_disconnected.set()
self.num_cancelled += 1
if is_global_aiohttp_client_request_debug_enabled() or self.num_cancelled % 100 == 0:
Expand Down
4 changes: 4 additions & 0 deletions resources_servers/swebench/configs/swebench.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ swebench_resources_server: # instance name — how agents/CLI refer to
ttl_s: 18000
ready_timeout_s: 1200
derive_cpu_env: true
env:
# execd holds each finished command's response open for this long (default 1s);
# a short grace keeps every command and the readiness probe from paying that tail.
EXECD_API_GRACE_SHUTDOWN: "50ms"
resources:
cpu: 2
memory_mib: 16384
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ terminal_bench_2_1_resources_server: # instance name — how agents/CLI
ttl_s: 18000
ready_timeout_s: 1200
derive_cpu_env: true
env:
# execd holds each finished command's response open for this long (default 1s);
# a short grace keeps every command and the readiness probe from paying that tail.
EXECD_API_GRACE_SHUTDOWN: "50ms"
resources:
cpu: 4
memory_mib: 16384
Expand Down
1 change: 1 addition & 0 deletions responses_api_agents/opencode_sandboxed_agent/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,7 @@ async def _start_sandbox(self, sandbox_id: Optional[str] = None) -> AsyncSandbox
resources = SandboxResources.from_mapping(self.config.sandbox_config.get("resources", {}))
# TODO @bxyu-nvidia: Refactor this after swapping to PTY as this should be set on the SWE Bench resources server side
env = cpu_cap_env(resources.cpu) if self.config.sandbox_config.get("derive_cpu_env", True) else {}
env |= dict(self.config.sandbox_config.get("env", {})) # explicit keys win over the derived caps

# TODO @bxyu-nvidia: Refactor this after Hemil's swap from Python dataclass to Pydantic BaseModel
sandbox_spec = SandboxSpec(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ opencode_sandboxed_agent:
sandbox_config:
ttl_s: 18000
ready_timeout_s: 1200
env:
# execd holds each finished command's response open for this long (default 1s);
# a short grace keeps every command and the readiness probe from paying that tail.
EXECD_API_GRACE_SHUTDOWN: "50ms"
resources:
cpu: 0.25
memory_mib: 512
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,14 @@ async def created_spec(sandbox_config: Dict[str, Any]) -> Any:
assert (await created_spec({"resources": {"cpu": 2}, "derive_cpu_env": False})).env == {}
assert (await created_spec({"resources": {"memory_mib": 8192}})).env == {}

# Explicit sandbox_config.env is passed through and wins over the derived caps.
spec = await created_spec(
{"resources": {"cpu": 2}, "env": {"EXECD_API_GRACE_SHUTDOWN": "50ms", "OMP_NUM_THREADS": "4"}}
)
assert spec.env["EXECD_API_GRACE_SHUTDOWN"] == "50ms"
assert spec.env["OMP_NUM_THREADS"] == "4"
assert all(spec.env[name] == "2" for name in CPU_CAP_ENV_VARS if name != "OMP_NUM_THREADS")

@fixture
def opencode_export_test_data(self) -> Dict[str, Any]:
test_data_path = Path(__file__).parent / "opencode_export_test_data.json"
Expand Down
24 changes: 14 additions & 10 deletions responses_api_agents/terminus_2_sandboxed_agent/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

from fastapi import Request
from harbor.agents.terminus_2 import Terminus2
from harbor.llms.base import BaseLLM, LLMResponse
from harbor.llms.base import BaseLLM, ContextLengthExceededError, LLMResponse
from harbor.models.agent.context import AgentContext
from harbor.models.metric.usage_info import UsageInfo
from harbor.utils.logger import logger as harbor_logger
Expand Down Expand Up @@ -92,6 +92,7 @@ class Terminus2AgentVerifyResponse(BaseVerifyResponse):
terminus2_time_taken: float
model_calls_gt_10min: int
num_compactions: int
error: Optional[str]


class NeMoGymSandboxEnvironment:
Expand Down Expand Up @@ -193,8 +194,8 @@ async def call(self, prompt: str, **kwargs: Any) -> LLMResponse:
input_items = self._input_items(message_history, prompt)
response = None
start_time = perf_counter()
max_attempts = 3 # Hardcode 3 attempts for now
for attempt in range(max_attempts):
max_attempts = 10 # Hardcode 10 attempts for now
for _ in range(max_attempts):
try:
async with asyncio.timeout(delay=60 * 10): # Hardcoded to match litellm default timeout
response = NeMoGymResponse.model_validate(
Expand All @@ -206,10 +207,7 @@ async def call(self, prompt: str, **kwargs: Any) -> LLMResponse:
break
except TimeoutError:
self._model_calls_gt_10min += 1
print(
f"Hit LiteLLM default 10min timeout on model call, attempt {attempt + 1} / {max_attempts}",
file=sys.stderr,
)

self._times_spent.append(perf_counter() - start_time)
if not response:
raise TimeoutError(f"Failed to query model endpoint due to timeouts after {max_attempts} attempts!")
Expand All @@ -231,6 +229,11 @@ async def call(self, prompt: str, **kwargs: Any) -> LLMResponse:
cost_usd=0.0,
)
content, reasoning_content = self._response_text(response)

# @bxyu-nvidia: Gym will return an empty model response when context length is exceeded
if not (content or reasoning_content):
raise ContextLengthExceededError

return LLMResponse(
content=content,
reasoning_content=reasoning_content,
Expand Down Expand Up @@ -259,9 +262,6 @@ def __init__(self, *args: Any, llm: NeMoGymLLM, dump_trajectory: bool, **kwargs:
def _init_llm(self, *args: Any, **kwargs: Any) -> BaseLLM:
return self._nemo_gym_llm

def _count_total_tokens(self, chat: Any) -> int:
return sum(len(str(message.get("content", ""))) // 4 for message in chat.messages)

def _dump_trajectory_with_continuation_index(self, continuation_index: int) -> None:
if self._dump_trajectory_enabled:
super()._dump_trajectory_with_continuation_index(continuation_index)
Expand Down Expand Up @@ -354,10 +354,13 @@ async def _execute(
async with asyncio.timeout(self.config.sandbox_timeout):
await agent.run(instruction, environment, context)
terminus2_completed = True
error = None
except TimeoutError:
terminus2_completed = False
error = format_exc()
except:
terminus2_completed = False
error = format_exc()
print(f"Hit exception while running Terminus2: {format_exc()}", file=sys.stderr)
finally:
pass
Expand Down Expand Up @@ -397,6 +400,7 @@ async def _execute(
"terminus2_time_taken": total_time,
"model_calls_gt_10min": llm._model_calls_gt_10min,
"num_compactions": agent._num_compactions,
"error": error,
}
return response, metrics

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
import orjson


fpath = "temp.jsonl"

gt_10 = 0
num_stuck = 0
num_is_covered = 0
num_model_call_long = 0
total = 0
with open(fpath, "rb") as f:
for i, line in enumerate(f):
row = orjson.loads(line)

count = 0
stuck_count = 0
for output_item in row["response"]["output"]:
if output_item.get("role") == "user":
content = output_item["content"]
count += "No valid JSON found in response" in content
elif output_item.get("type") == "reasoning":
content = output_item["summary"][0]["text"]
stuck_count += "stuck" in content or "unresponsive" in content

is_gt_10 = count > 10
was_stuck = stuck_count > 10
model_call_long = row["model_calls_gt_10min"] >= 6
is_covered = is_gt_10 or was_stuck or model_call_long
if not is_covered:
print(f"{i + 1}: {count > 10=} {was_stuck=} {model_call_long=}")

num_model_call_long += model_call_long
num_stuck += was_stuck
gt_10 += is_gt_10
num_is_covered += is_covered
total += 1

print(gt_10, num_stuck, num_model_call_long, num_is_covered, total)
64 changes: 64 additions & 0 deletions tests/unit_tests/test_server_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from nemo_gym.server_utils import (
BaseServer,
BaseServerConfig,
ClientDisconnectCancellationMiddleware,
ConnectionError,
DictConfig,
GlobalAIOHTTPAsyncClientConfig,
Expand Down Expand Up @@ -628,6 +629,69 @@ async def send(message):
assert handler_cancelled.is_set()
assert sent_messages == []

async def test_cancellation_middleware_ignores_disconnect_after_response_completion(self) -> None:
response_sent = asyncio.Event()
finish_cleanup = asyncio.Event()
cleanup_completed = asyncio.Event()
handler_cancelled = asyncio.Event()

async def inner_app(scope, receive, send) -> None:
assert await receive() == {"type": "http.request", "body": b"", "more_body": False}
await send({"type": "http.response.start", "status": 200, "headers": []})
await send({"type": "http.response.body", "body": b"ok", "more_body": False})
try:
await finish_cleanup.wait()
except asyncio.CancelledError:
handler_cancelled.set()
raise
cleanup_completed.set()

middleware = ClientDisconnectCancellationMiddleware(inner_app)
request_delivered = False

async def receive():
nonlocal request_delivered
if not request_delivered:
request_delivered = True
return {"type": "http.request", "body": b"", "more_body": False}

await response_sent.wait()
return {"type": "http.disconnect"}

sent_messages = []

async def send(message):
sent_messages.append(message)
if message["type"] == "http.response.body" and not message.get("more_body", False):
response_sent.set()

scope = {
"type": "http",
"asgi": {"version": "3.0"},
"http_version": "1.1",
"method": "POST",
"scheme": "http",
"path": "/work",
"raw_path": b"/work",
"query_string": b"",
"headers": [],
"client": ("127.0.0.1", 1234),
"server": ("testserver", 80),
}
app_task = asyncio.create_task(middleware(scope, receive, send))
await asyncio.wait_for(response_sent.wait(), timeout=1)
await asyncio.sleep(0)
finish_cleanup.set()
await asyncio.wait_for(app_task, timeout=1)

assert cleanup_completed.is_set()
assert not handler_cancelled.is_set()
assert middleware.num_cancelled == 0
assert sent_messages == [
{"type": "http.response.start", "status": 200, "headers": []},
{"type": "http.response.body", "body": b"ok", "more_body": False},
]

def test_upstream_error_log_has_bounded_body_and_redacted_url(self) -> None:
request_info = RequestInfo(
url=URL("http://policy.test/v1/responses?api_key=secret"),
Expand Down
Loading