Skip to content

Navigation Menu

Sign in
Sign up

feat(shell): adaptive timeouts and a wait-for-condition primitive #3382

Description

Waiting is where the agent most often fails. The shell tool defaults to a 30-second timeout, far below what a test suite, a build or an install needs, so long commands get killed rather than finished.

The default is the defect, not the ceiling: timeout is already a declared parameter on the tool, so the model can raise it — it rarely does, because nothing tells it how long the command it is about to run should take. A default that is wrong for the common case, with no signal to correct it, behaves like a hard limit.

There is also no way to wait for a condition. An agent that needs to wait for a server to come up, or a CI run to finish, has only one option: sleep in a loop and re-check. That is what a user sees as the agent spinning and doing nothing, and it burns steps against the loop's cap for no work.

Acceptance criteria

  • Timeouts adapt to a named, enumerated set of command classes with a stated default per class — e.g. test runners, builds/installs, VCS and network calls, everything else. A contributor must be able to check the table off.
  • A wait-for-condition primitive exists: a predicate plus a deadline, with a stated poll interval and a bounded maximum wait, so sleeping in a loop is unnecessary.
  • Tests cover each timeout class and the wait primitive's deadline expiry, and assert the three already-true behaviours below have not regressed.

Already true — must not regress

Three things already work and a contributor should not rebuild them: the applied timeout is already returned in the result, a timed-out command is already distinguishable via a dedicated flag, and partial stdout/stderr is already captured and returned on timeout.

🔍 Technical details

run_shell_command in src/gaia/agents/tools/shell_tools.py takes timeout: int = 30, passed straight to subprocess.run. The agent-level tool timeout is separate and much larger, which means a shell command can be killed at 30s inside a step that had minutes of budget.

The TimeoutExpired handler already captures exc.stdout / exc.stderr and returns them with timed_out: True — that behaviour is good and is the thing to build on, not replace.

The wait primitive should not be built out of sleep internally either; a deadline plus a predicate check is what is wanted, so that the step cost is one call rather than one call per poll.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request p2low priority

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    AltStyle によって変換されたページ (->オリジナル) /