Closed
Conversation
- Add tabbed interface showing both subprocess.run and subprocess.Popen approaches - Add "Understanding subprocess.Popen" info section with Python docs reference - Link to OpenHands Software Agent SDK as production example
Open
Member
|
Thanks! but what advantage does that have over |
Contributor
Author
|
You're right that if we just call The advantages of 1. Agent with parallel executionimport subprocess
from subprocess import PIPE
def execute_action(command: str) -> str:
"""Execute action, supports parallel commands with 'parallel:' prefix"""
# Parallel execution: parallel:npm install && eslint .
if command.startswith("parallel:"):
commands = command[9:].split(" && ")
processes = []
# Start all processes
for cmd in commands:
proc = subprocess.Popen(
cmd.strip(),
shell=True,
stdout=PIPE,
stderr=subprocess.STDOUT,
text=True
)
processes.append((cmd.strip(), proc))
# Wait for all and collect output
results = []
for cmd, proc in processes:
output, _ = proc.communicate()
results.append(f"[{cmd}]\n{output}")
return "\n---\n".join(results)
# Normal blocking command
result = subprocess.run(
command,
shell=True,
text=True,
stdout=PIPE,
stderr=subprocess.STDOUT,
timeout=30,
)
return result.stdoutThe agent could run Output: 2. Agent with persistent shell sessionimport subprocess
from subprocess import PIPE
class PersistentShell:
def __init__(self):
self.proc = subprocess.Popen(
["bash"],
stdin=PIPE,
stdout=PIPE,
stderr=subprocess.STDOUT,
text=True,
bufsize=1
)
def execute(self, command: str) -> str:
end_marker = f"__END_{id(command)}__"
self.proc.stdin.write(f"{command}\n")
self.proc.stdin.write(f"echo '{end_marker}'\n")
self.proc.stdin.flush()
output = []
for line in self.proc.stdout:
if end_marker in line:
break
output.append(line)
return "".join(output)
shell = PersistentShell()
def execute_action(command: str) -> str:
return shell.execute(command)
# cd and env vars persist between commands3. Agent with streaming output (see shell output)import subprocess
from subprocess import PIPE
def execute_action(command: str) -> str:
proc = subprocess.Popen(
command,
shell=True,
stdout=PIPE,
stderr=subprocess.STDOUT,
text=True
)
output_lines = []
for line in proc.stdout:
output_lines.append(line)
print(f"[live] {line}", end="") # Agent sees output as it happens
# React to specific patterns
if "error" in line.lower():
proc.kill()
output_lines.append("\n[Agent: Detected error, stopping process]")
break
if len(output_lines) > 500:
proc.kill()
output_lines.append("\n[Agent: Output too long, stopping]")
break
proc.wait()
return "".join(output_lines)The agent sees For the current minimal agent, subprocess.run() is indeed simpler and sufficient. Popen would make sense if we wanted to add features mentioned above. |
Contributor
Author
|
Closing — |
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.
Summary
subprocess.runandsubprocess.Popenapproaches