Skip to content

feat(tools): support per-subagent remote workspaces - #4980

Open
sohamb117 wants to merge 6 commits into
OpenHands:mainfrom
sohamb117:feat/subagent-remote-workspaces
Open

sohamb117 wants to merge 6 commits into
OpenHands:mainfrom
sohamb117:feat/subagent-remote-workspaces

Conversation

@sohamb117

@sohamb117 sohamb117 commented Sep 12, 2026

Copy link
Copy Markdown

HUMAN:

Why

Currently, there are primitives that support executing agents in sandboxes/remotely. However, this feature is not extended to subagents. This PR provides that capacity, extending primitives for remote execution to subagents.

Summary

We add an optional Workspace Factory to TaskManager that allows remote workspaces to be created or connected for subagents.

Issue Number

Addresses #5195


AGENT:

Why

A local parent should be able to delegate work to isolated remote sandboxes without replacing its own workspace or introducing a scheduler/provider abstraction.

Summary

  • Add an optional workspace_factory(child_id, agent_type) -> RemoteWorkspace | None to TaskManager, TaskToolSet.create, and DelegateExecutor. Returning None preserves local execution.
  • Own each remote child's conversation and workspace; preserve result delivery, confirmation approve/reject, tracing, and in-session Task resume. Provision outside the TaskManager lock with pending ownership reservations and failure cleanup.
  • Forward max_budget_per_run through the remote request/server path, and add unit, real-server, and real-GPT-5-mini Docker coverage.

Issue Number

Addresses #5195

How to Test

Post-rebase validation on upstream 9c3571a6, SDK feature head a72b80ef:

uv sync --frozen --dev
.venv/bin/pytest tests/tools/test_remote_subagents.py tests/tools/task tests/tools/delegate tests/sdk/conversation/remote tests/agent_server/test_models.py tests/agent_server/test_event_service.py tests/agent_server/test_conversation_service.py -q --disable-warnings --maxfail=3
.venv/bin/pytest tests/cross/test_remote_conversation_live_server.py -k 'remote_subagent or subagent_workspace_factory_returns_result' -q --disable-warnings --maxfail=2

Results: 489 passed and 4 passed, respectively. The cross-tests use real HTTP and WebSockets with a deterministic LLM and cover Task/Delegate result return and remote budget enforcement.

Real-model reproduction (Docker/Colima required):

# Set LLM_API_KEY securely in the environment; never put it in --llm-config.
export LLM_BASE_URL=https://api.openai.com/v1
uv run python tests/integration/run_infer.py \
  --llm-config '{"model":"openai/gpt-5-mini","reasoning_effort":"low","max_output_tokens":4096,"num_retries":1}' \
  --tool-preset gpt5 \
  --eval-ids t10_remote_subagent_workspaces

The test builds a minimal source image from the current checkout. To reuse a matching local image, set AGENT_SERVER_IMAGE.

Observed real-model run before the final rebase: local GPT-5-mini parent → two distinct Docker workspaces → remote child terminal/finish execution → resume both original tasks → exact private file contents/results → unchanged parent file → both HTTP clients closed and containers removed. PASS, 165.75 seconds, reported total cost $0.0196272. No LLM or transport mocking in this run.

That run used the feature source later committed as 58a5a2d1 and an SDK 1.46.0 image built from the same working tree. Its feature changes were rebased unchanged; the real paid Docker scenario has not been rerun with an SDK 1.47.0 image after the final rebase. The four real-server cross-tests above were rerun after rebase.

Video/Screenshots

Non-UI feature. Representative real-model runner output:

t10_remote_subagent_workspaces completed in 165.75s: PASS
Real LLM parent delegated to two Docker children, resumed both,
received their private results, and released both sandboxes.
Overall Success rate: 100.00% (1/1)

Local full report and logs:
tests/integration/outputs/openai_gpt_5_mini_gpt5-mini-colima-minimal_N1_20260911_232029/.
These generated artifacts are not tracked. They were checked for API-key-shaped text; none was present.

Design Doc

The factory/ownership contract and examples are documented in the companion docs change:
OpenHands/docs#791,
branch feat/subagent-remote-workspaces, commit 4a905c81.

Type

  • Bug fix
  • Feature
  • Refactor
  • Breaking change
  • Docs / chore

Notes

  • Remote Task workspaces remain allocated until TaskManager.close(); Delegate owns workspaces until close or child replacement.
  • Resume is limited to the same manager instance. No manifests, persistent workspace identities, resolver API, cross-process restoration, or replacement provisioning on resume.
  • A plain RemoteWorkspace does not destroy an externally managed server on exit; workspace subclasses own infrastructure teardown.
  • Each factory result must represent a distinct sandbox. Object-identity checks reject sharing one workspace object; the factory must not wrap the same sandbox twice.
  • Budgeted remote creation fails explicitly if the server does not acknowledge the budget.
  • Formatting, Ruff, Pyright, import rules, tool registration, and diff whitespace checks passed.
  • Known upstream lint blocker: the whole-SDK forbidden-dynamic-attributes hook fails identically on pristine upstream 9c3571a6 at agent/stream_context.py:287 and llm/utils/telemetry.py:264,270,272. These files are unchanged by this PR. The same checker passes on the SDK files changed here. The full pre-commit run is therefore not green.
  • GitHub CI and benchmark/evaluation review remain pending. Request the integration-test label and human review before merge.

Jev-Fast-Audit

Jev fast audit · estimates · 0.58s · commit c557255
Strongest signal: No primary concern selected.
Evidence: No primary concern to locate.
Coverage: ⚠️ reduced context — partial coverage; 32/130 hunks, 8/31 files (context budget: 32, file budget: 23, hunk budget: 98).

All estimates and evidence
Estimate Likelihood / value Direct evidence
SQL injection 4.0% No direct hunk selected
Command injection 15.0% No direct hunk selected
Weakened authentication 10.0% No direct hunk selected
Weakened authorization 16.0% No direct hunk selected
Contract regression 20.0% No direct hunk selected
Data loss 8.0% No direct hunk selected
Sensitive data disclosure 9.0% No direct hunk selected
Unexpected data transfer 8.0% No direct hunk selected
Credential misuse 10.0% No direct hunk selected
Untrusted instruction authority 5.0% No direct hunk selected
Package source redirection 5.0% No direct hunk selected
Unverified remote execution 4.0% No direct hunk selected
Privileged environment access 12.0% No direct hunk selected
Security assessment bypass 8.0% No direct hunk selected
Prohibited workload 3.0% No direct hunk selected
Primary concern None selected; confidence 80.0% No primary concern to locate

@github-actions

github-actions Bot commented Sep 20, 2026

Copy link
Copy Markdown
Contributor
  ✅ **PR Artifacts Cleaned Up**

  The `.pr/` directory is no longer present.

@sohamb117
sohamb117 force-pushed the feat/subagent-remote-workspaces branch from 255e068 to c557255 Compare September 20, 2026 22:23
@sohamb117
sohamb117 marked this pull request as ready for review September 20, 2026 22:24
@all-hands-bot

Copy link
Copy Markdown
Collaborator

🚦 CI is currently failing on this PR's latest commit.

Please fix the failing checks before OpenHands reviews it - this is re-checked automatically once you push a new commit. (A maintainer can also request @all-hands-bot as a reviewer to have it reviewed regardless of CI status.)

This is an automated check - no AI was used to generate this comment.

@sohamb117
sohamb117 force-pushed the feat/subagent-remote-workspaces branch from c557255 to 47412dc Compare September 20, 2026 23:30
@sohamb117

Copy link
Copy Markdown
Author

@enyst This is ready for review and addresses #5195. The fork CI runs are currently sitting at action_required; could you authorize them when you get a chance?

@sohamb117

Copy link
Copy Markdown
Author

@xingyaoww @neubig
🥺🥺🥺

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