Skip to content

Navigation Menu

Sign in
Sign up

feat(shell): one persistent shell per task so cwd and env survive #3380

Description

Every shell command GAIA runs starts from scratch. The working directory, environment variables and any activated virtualenv are discarded the moment the command returns, so the next call begins from the same cold state. An agent that activates a venv and then runs pip list gets the wrong answer; an agent that changes directory and then runs a build gets the wrong directory.

Per-call working directory is expressible — run_shell_command takes a working_directory argument. Exported environment variables and virtualenv activation are the real gap, and there is no way to express those at all: the usual workaround is chaining setup onto the real command, which the operator block refuses until #3373 lands.

Acceptance criteria

  • One long-lived shell process per task; cwd, exported environment and venv activation persist across calls.
  • The session is torn down deterministically at task end, with no orphaned process left behind on any supported platform.
  • A probe lets the agent read the current cwd and environment rather than inferring it.
  • Access to a session is serialised. Parallel tool_calls are executed sequentially by the loop, so that path is not the hazard — the real one is fix(agents): abandoned tool-timeout threads leak log records and state into unrelated code #2600 : a tool call that exceeds its timeout leaves its worker thread running, so a timed-out command can still be inside the subprocess when the next call starts. Against a shared session that is exactly the corruption this guards.
  • A reset is available so a wedged session can be recovered without ending the task.
  • Per-segment command validation continues to apply exactly as it does today; persistence is about state, not about policy.
🔍 Technical details

run_shell_command in src/gaia/agents/tools/shell_tools.py calls subprocess.run(..., cwd=cwd, env=os.environ.copy()) per invocation, where cwd defaults to Path.cwd() or an explicit per-call argument. There is no session object, no persistent process, and no place for state to live.

The teardown requirement is the risky part, not the persistence: a long-lived child that outlives its parent is a stray process, and #3230 already dealt with a stray-process class in the daemon tests. Whatever lifecycle this uses needs the same scrutiny.

Prior art: do not start from scratch. #2810 (closed) shipped ShellSession for the C++ toolbelt in cpp/include/gaia/process.h. Its design already resolves every hard part listed above — per-session mutex serialisation, no parent-process mutation, cwd/env round-trip via a side file, stdin detached, POSIX process-group kill on timeout, and the Windows cmd.exe caveat. Port that design.

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 によって変換されたページ (->オリジナル) /