Skip to content

examples: add swe-agent-harbor-daytona (Harbor sandboxes on Daytona) - #1919

Merged
Shi-Dong merged 7 commits into
mainfrom
shi/swe-agent-daytona-example
Aug 6, 2026
Merged

examples: add swe-agent-harbor-daytona (Harbor sandboxes on Daytona)#1919
Shi-Dong merged 7 commits into
mainfrom
shi/swe-agent-daytona-example

Conversation

@Shi-Dong

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

Copy link
Copy Markdown
Contributor

Summary

Adds examples/swe-agent-harbor-daytona, a variant of examples/swe-agent whose
task sandboxes run on Daytona cloud sandboxes instead
of local Docker.

Two things differ from examples/swe-agent:

  • Daytona sandboxes. The agent-server host needs outbound HTTPS but no
    Docker daemon, no local image builds, and no local disk for task images. This
    is the practical option when the trainer runs on a GPU node where you cannot
    run Docker-in-Docker.
  • terminus-2 agent. terminus-2 runs as a host process and calls the model
    endpoint itself rather than from inside the sandbox. It appends both user
    and tool turns, so the session server needs
    --tito-allowed-append-roles user tool. Without it every append is rejected,
    trajectories collapse to a single turn, and the session server rolls them
    back. That flag is the reason this needs its own launcher instead of a README
    pointing at examples/swe-agent/run.py.

Everything else — TITO, the session server, GRPO, the reward path — is shared
with examples/swe-agent, so run.py puts that example on PYTHONPATH and
imports its generate.py and swe_agent_function.py rather than keeping a
second copy in sync. Data prep also reuses
examples/swe-agent/download_and_process_data.py, with --agent-name terminus-2.

Contents

File Purpose
README.md Provision Daytona, start the agent server, prepare data, launch training, verify progress, troubleshoot.
run.py Training launcher for Daytona-backed terminus-2 runs.
launch_agent_server.sh Starts the Harbor agent server in Daytona mode.

The README also writes down the failure modes that cost the most time on a
multi-day run of this shape:

  • --rollout-max-response-len and AGENT_MAX_OUTPUT_TOKENS cap a single
    turn
    , not the whole trajectory. Under HARBOR_RESPONSE_LENGTH_POLICY=abort
    an over-cap turn ends the trial with none of that turn's tool calls performed,
    so the trial scores 0 and dilutes its GRPO group.
  • Read rollout/raw_reward for the solve rate; rollout/rewards is the
    GRPO-centered advantage and sits near zero by construction.
  • When censusing trial directories by outcome, key on the trial's start time
    (the mtime of its config.json), because writing exception.txt bumps the
    directory mtime and makes any mtime-sorted listing look like everything is
    failing.

Two launcher settings that are hardcoded in examples/swe-agent/run.py are
exposed as flags here, since they are the ones you actually end up tuning:
--rollout-max-response-len and --max-tokens-per-gpu (plus --lr and
--sglang-mem-fraction-static).

--router-external-host defaults to the resolved local IP. sgl-router parses
this into a Rust SocketAddr, so it must be a numeric IP and a hostname fails
to bind. The default is computed in a helper guarded against resolution
failure, so an unresolvable hostname cannot break module import.

Test plan

  • python -m py_compile examples/swe-agent-harbor-daytona/run.py
  • bash -n examples/swe-agent-harbor-daytona/launch_agent_server.sh
  • ruff check examples/swe-agent-harbor-daytona/run.py
  • Pipeline validated end-to-end by a multi-day GLM-4.7-Flash run on one node
    of 8 H200 GPUs against Terminal-Bench 2 tasks, reaching non-zero
    rollout/raw_reward with the agent server colocated on the trainer host.
  • Docs-and-example change; no library code is touched, so no existing test
    covers it.

Adds a SWE-agent example whose task sandboxes run on Daytona cloud
sandboxes instead of local Docker, so the trainer host needs no Docker
daemon and no local task-image builds.

The agent is terminus-2, which runs as a host process and appends both
user and tool turns, so the session server needs
--tito-allowed-append-roles user tool. That flag is the reason this
needs its own launcher rather than reusing examples/swe-agent/run.py.

generate.py and swe_agent_function.py are unchanged for Daytona-backed
runs, so run.py puts the sibling example on PYTHONPATH instead of
duplicating them.
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

Comment thread examples/swe-agent-harbor-daytona/launch_agent_server.sh Outdated
Comment thread examples/swe-agent-harbor-daytona/README.md Outdated
Comment thread examples/swe-agent-harbor-daytona/README.md Outdated
Comment thread examples/swe-agent-harbor-daytona/README.md Outdated
Shi-Dong added 2 commits July 28, 2026 15:02
- rename the example directory to swe-agent-harbor-daytona
- name the harbor branch (harbor-miles-v0.20.0) in launch_agent_server.sh
- trim the Daytona disk-quota discussion down to the sizing rule
- refer to sibling files by their path from the repo root, not ../swe-agent
- drop the troubleshooting row for a missing --tito-allowed-append-roles,
  which run.py always passes
- name the harbor branch (harbor-miles-v0.20.0) in launch_agent_server.sh
- trim the Daytona disk-quota discussion down to the sizing rule
- refer to sibling files by their path from the repo root, not ../swe-agent
- drop the troubleshooting row for a missing --tito-allowed-append-roles,
  which run.py always passes
- follow the directory rename through paths and default run names
@Shi-Dong Shi-Dong changed the title examples: add swe-agent-daytona (Harbor sandboxes on Daytona) examples: add swe-agent-harbor-daytona (Harbor sandboxes on Daytona) Jul 28, 2026
Comment thread examples/swe-agent-harbor-daytona/README.md Outdated
Comment thread examples/experimental/swe-agent-harbor-daytona/README.md
- say up front that the example targets a single node of 8 H200 GPUs, and
  drop the now-duplicated hardware note from the launch section
- reference examples/swe-agent as plain text rather than a relative link
- spell out rollout/response_len/max instead of abbreviating it as .../max
@nblintao
nblintao self-requested a review August 3, 2026 23:13
@@ -0,0 +1,284 @@
"""SWE-Agent launcher (GLM-4.7-Flash) for Harbor tasks on Daytona sandboxes.

Same Miles <-> Harbor pipeline as examples/swe-agent, with two differences:

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.

Do you think we should rename swe-agent to something like swe-agent-harbor-docker? or should we should better keep the url slug unchanged?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good idea. Opened PR 2233 to handle the renaming.

Comment thread examples/experimental/swe-agent-harbor-daytona/run.py Outdated
--host 0.0.0.0 \
--port "$PORT" \
--max-concurrent "$MAX_CONCURRENT" \
--agent-timeout 5400 \

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.

examples/swe-agent/swe_agent_function.py harcoded to

        response = await asyncio.wait_for(
            _post_agent_server(f"{agent_server_url}/run", request),
            timeout=3600,  # 1 hour max per trial

so the server will still be running after the agent function gives up.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Opened a follow-up PR 2228 to address this comment.

…nt/run.py

The launcher only existed because terminus-2 needed
--tito-allowed-append-roles. #1818 removed that flag and added a test
asserting it is rejected, so the launcher could no longer start a run.

Nothing else in it was Daytona-specific: Daytona is selected entirely by
the agent server's environment, which the trainer never sees. The four
values it exposed as flags all defaulted to what examples/swe-agent/run.py
already hardcodes, so reusing that launcher is behaviourally identical.

Also corrects --router-external-host: it is substituted into the base URL
handed to the agent and only has to resolve from the agent-server host, so
a hostname is fine. The bind-time constraint belongs to --miles-host-ip.
@Shi-Dong
Shi-Dong merged commit 41b9ae2 into main Aug 6, 2026
45 checks passed
@Shi-Dong
Shi-Dong deleted the shi/swe-agent-daytona-example branch August 6, 2026 21:53
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.

2 participants