Repository navigation
feat(agent-server): allow bash timeout=None to run until stopped - #6052
Open
Jacob-Lasky wants to merge 2 commits into
Open
Jacob-Lasky wants to merge 2 commits into
Jacob-Lasky wants to merge 2 commits into
Conversation
ExecuteBashRequest.timeout accepts null (default stays 300). A command
started through start_bash_command or the bash websocket with a null
timeout runs until it exits or is stopped through
POST .../bash_commands/{command_id}/stop. The blocking
execute_bash_command answers 422 for a null timeout, since it would
hold the request open with no id to stop the command.
SDK: RemoteWorkspace/AsyncRemoteWorkspace.start_command accept
timeout=None and send it as null, leaving the start request on the
client's HTTP timeout; execute_command rejects None with ValueError
before sending anything.
TypeScript client: BashClient.startCommand forwards a null timeout
unchanged (Math.floor(null) used to send 0), executeCommand rejects
null before sending, and ExecuteBashRequest.timeout is number | null.
Adds F13.timeout-none to the verify-agent-server feature map.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Jacob-Lasky
marked this pull request as ready for review
October 17, 2026 16:48
Co-authored-by: openhands <openhands@all-hands.dev>
Contributor
|
📁 PR Artifacts Notice This PR contains a |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
HUMAN:
Allow for a CLI command to run without a timeout. Many of my commands take a few minutes, especially rust builds and test suites.
AGENT:
Why
Long build commands are often supervised by the caller, which decides when they should end and uses
POST /api/bash/bash_commands/{command_id}/stop(added in #5348) to end them. For those commands an arbitrary server-side timer is the wrong control: there is no correct number. Today the only way to start a command with no deadline is to replace the privateBashEventService._execute_bash_command.Summary
ExecuteBashRequest.timeoutis nowint | None, with the default unchanged at 300.nullonstart_bash_commandand the bash websocket means the command runs until it exits or is stopped.execute_bash_commandroute returns 422 fornull, because a command that never exits would otherwise hang the request with no id to stop it. The 422 points callers atstart_bash_commandplus the stop route.RemoteWorkspace.start_commandandAsyncRemoteWorkspace.start_commandaccepttimeout=Noneand sendnull.execute_commandrejectsNonewith aValueErrorbefore any request, sync and async.startCommandforwardsnullunchanged,executeCommandrejects it before sending, andExecuteBashRequest.timeoutisnumber | null.F13.timeout-nonesub-feature and its recipe, which includes the 422 check.bash_events_retention_secondsdescription now says "run time" instead of "timeout".Issue Number
None opened. The motivation comes from a downstream deployment that currently patches
_execute_bash_command.How to Test
All new tests are additions; no existing test is removed or renamed.
tests/agent_server/test_bash_service.pytest_execute_bash_request_timeout_defaults_to_300_and_accepts_nulltest_bash_command_without_timeout_runs_until_stopped: the wait receivesNone, the command is still running after 1.5s, and stop ends it with -15.test_bash_command_default_timeout_bounds_the_wait: the wait receives exactly 300.test_execute_bash_command_rejects_null_timeouttests/sdk/workspace/remote/test_remote_workspace_mixin.pytest_start_command_generator_sends_null_timeouttest_execute_command_generator_rejects_none_timeout_before_startingtests/sdk/workspace/remote/test_runtime_scope.py:test_execute_command_rejects_none_timeout_before_any_request, sync and async.tests/cross/test_remote_conversation_live_server.py:test_start_command_without_timeout_runs_until_stopped_with_live_server, a real server.BashClient.startCommand forwards a null timeout unchangedBashClient.executeCommand rejects a null timeout before sendingRed-then-green. With the source change reverted and the new tests kept, the model, service, SDK-generator and live-server tests fail, as does the map recipe. The default-300 test passes either way; it guards the default.
Gates:
uv run pre-commit runon the changed files482 passed, 1 skipped, three runs3 passedmap checkokmap run --file F13 --only F13.timeout-none --freshon a real serverpass: 2, fail: 0389 passed, public type budget unchangedVideo/Screenshots
Not applicable. There are no visual changes.
Design Doc
Skipped. The change is additive: one field accepts
null.Type
Notes
Commands started on the process-global bash service. A command started with
timeout: nullon the process-global bash service, through/api/bash/start_bash_commandor the bash websocket, is not stopped when an in-process app lifespan exits.nullremoves that bound.POST /api/bash/bash_commands/{command_id}/stop(orRemoteWorkspace.stop_command/BashClient.stopCommand) before shutting down.Making the lifespan own the global service's lifetime takes more than closing it on exit:
I'm happy to send that as a separate PR.
Expect a
release-note-requiredlabel: theBashCommandresponse'stimeoutnow also allowsnull.