Skip to content

rollout: decouple oversampling-abort teardown into a pluggable agent hook#1639

Open
Shi-Dong wants to merge 3 commits into
mainfrom
shi/fix-oversampling-harbor-flush
Open

rollout: decouple oversampling-abort teardown into a pluggable agent hook#1639
Shi-Dong wants to merge 3 commits into
mainfrom
shi/fix-oversampling-harbor-flush

Conversation

@Shi-Dong

@Shi-Dong Shi-Dong commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Problem

With oversampling on, once the trainer has collected enough samples, the rollout aborts the in-flight SGLang generations via /abort_request {"abort_all": true}. But the external agent loops driving the agentic rollouts are never told.

Each aborted generation just looks like one finished LLM call to the agent, so the agent immediately issues the next completion request back to SGLang. The loops keep hammering SGLang and holding their sandbox containers until they independently hit their own max_seq_len / trial timeout — wasting inference during the drain and pinning containers.

Why not a hard-coded flush in core

Miles' core rollout is agent-host-agnostic: agentic_tool_call.generate delegates all agent-host knowledge to a plugin loaded from --custom-agent-function-path. Baking a Harbor-specific /flush call into the core rollout would wrongly assume every deployment uses a Harbor agent server that speaks /flush, which isn't always true.

Fix (pluggable hook, both sync and async paths)

  • Core stays agnostic. New miles.utils.misc.call_agent_abort_hook(args) looks for a sibling abort callable in the same module as the configured --custom-agent-function-path and awaits it if present. No hook → drain as before. Zero Harbor strings, no new core args. Non-agentic and non-Harbor runs are unaffected.
  • Wired into BOTH oversampling-abort implementations:
    • miles/rollout/sglang_rollout.py::abort — the legacy/sync path (default when MILES_EXPERIMENTAL_ROLLOUT_REFACTOR is unset).
    • miles/rollout/inference_rollout/inference_rollout_train.py::abort — the experimental-refactor path used by async training (train_async.py + MILES_EXPERIMENTAL_ROLLOUT_REFACTOR=1InferenceRolloutFn). This is the path Shi's agentic async runs actually take, so covering it is the point.
  • Harbor teardown lives in the plugin. The Harbor /flush logic is in examples/experimental/swe-agent-v2/swe_agent_function.py as its abort(args) hook — next to the AGENT_SERVER_URL + /run code it already owns. It flushes the agent server's in-flight /run trials for this run's session_server_instance_id (sending HARBOR_ADMIN_SECRET as a bearer token when present). No-op unless the URL + instance id are available.

No Harbor server change is needed — /flush already exists in harbor-miles-v0.13.1 and returns HTTP 200 on cancel.

Test plan

  • Sync agentic run (legacy path): on oversampling abort, plugin logs Flushed agent server ... and Harbor /run tasks terminate instead of continuing to call SGLang.
  • Async agentic run (train_async.py + refactor): same behavior via inference_rollout_train.abort.
  • Agentic run whose plugin defines no abort: call_agent_abort_hook is a silent no-op; drain unchanged.
  • Non-agentic (rule-based RM) run: custom_agent_function_path is None → hook lookup short-circuits; abort behavior unchanged.

When oversampling collects enough samples, abort() aborts the in-flight
SGLang generations but leaves the Harbor agent loops running. Those loops
keep issuing fresh completion requests to SGLang until they hit their own
max_seq_len / timeout, wasting inference and holding containers.

Flush the agent server's in-flight /run trials (agent-agnostic, so it works
for mini-swe-agent which bypasses harbor's lite_llm) right after the SGLang
abort so they stop hitting SGLang and release their containers. No-op unless
--agent-server-url / AGENT_SERVER_URL and session_server_instance_id are set.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the ability to flush in-flight Harbor agent-server trials when aborting SGLang rollouts. It adds a new --agent-server-url command-line argument and a corresponding flush_agent_server helper function that sends a POST request to the agent server's /flush endpoint. Feedback suggests stripping leading and trailing whitespaces from the agent server URL and the admin secret to prevent potential issues with malformed URLs or invalid authorization headers.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread miles/rollout/sglang_rollout.py Outdated
Comment on lines +352 to +360
agent_server_url = getattr(args, "agent_server_url", None) or os.environ.get("AGENT_SERVER_URL")
instance_id = getattr(args, "session_server_instance_id", None)
if not agent_server_url or not instance_id:
return

headers = None
admin_secret = os.environ.get("HARBOR_ADMIN_SECRET")
if admin_secret:
headers = {"Authorization": f"Bearer {admin_secret}"}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Environment variables and command-line arguments (especially URLs and secrets/tokens) are highly prone to containing accidental leading or trailing whitespaces or newlines (e.g., when loaded from .env files or Kubernetes secrets).

Why this matters:

  • URLs: Leading/trailing spaces can cause httpx to raise malformed URL or connection errors.
  • Secrets: Trailing newlines in HARBOR_ADMIN_SECRET will result in an invalid Authorization header, causing the Harbor agent server to reject the request with a 400 or 401 error.

Stripping these values before use ensures robust and reliable API calls.

Suggested change
agent_server_url = getattr(args, "agent_server_url", None) or os.environ.get("AGENT_SERVER_URL")
instance_id = getattr(args, "session_server_instance_id", None)
if not agent_server_url or not instance_id:
return
headers = None
admin_secret = os.environ.get("HARBOR_ADMIN_SECRET")
if admin_secret:
headers = {"Authorization": f"Bearer {admin_secret}"}
agent_server_url = getattr(args, "agent_server_url", None) or os.environ.get("AGENT_SERVER_URL")
instance_id = getattr(args, "session_server_instance_id", None)
if not agent_server_url or not instance_id:
return
agent_server_url = agent_server_url.strip()
headers = None
admin_secret = os.environ.get("HARBOR_ADMIN_SECRET")
if admin_secret:
headers = {"Authorization": f"Bearer {admin_secret.strip()}"}

Replace the hard-coded Harbor /flush in core sglang_rollout.abort() with a
generic, optional hook: it looks for a sibling abort() in the module named by
--custom-agent-function-path and calls it if present. Core Miles no longer
assumes the agent host speaks /flush; non-agentic and non-Harbor backends
just drain as before.

Move the Harbor /flush teardown into the swe_agent_function plugin (where the
agent-server URL and /run already live) as its abort() hook. Drop the core
--agent-server-url arg added earlier.
@Shi-Dong Shi-Dong changed the title rollout: flush Harbor agent server on oversampling abort rollout: decouple oversampling-abort teardown into a pluggable agent hook Jul 12, 2026
…ut) path

Async training (train_async.py + MILES_EXPERIMENTAL_ROLLOUT_REFACTOR=1) uses
InferenceRolloutFn, whose oversampling abort lives in inference_rollout_train.abort,
a separate implementation from sglang_rollout.abort. The previous commit only
wired the legacy sync path, so async agentic runs still leaked in-flight trials.

Hoist the hook resolver into miles.utils.misc.call_agent_abort_hook (shared, no
new cross-module dep) and call it from both abort paths.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant