Skip to content

Commit 969f29a

Browse files
sjarmakclaude
andcommitted
fix: use Python launcher to bypass shell expansion in OpenHands task arg
The previous base64 fix decoded the instruction to a file but still used $(cat file) inside double quotes for --task=, causing bash to interpret the file content as shell code (syntax errors on backticks, single quotes, etc). Now we write a small Python launcher script that reads the task file and passes it as a proper sys.argv element to openhands.core.main, completely bypassing shell quoting. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent dc195d9 commit 969f29a

File tree

1 file changed

+23
-8
lines changed

1 file changed

+23
-8
lines changed

agents/harnesses/openhands/agent.py

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -129,21 +129,36 @@ def create_run_agent_commands(self, instruction: str):
129129
env=env,
130130
))
131131

132-
# Build the openhands command reading task from file
132+
# Build a Python launcher script that reads the task from file and
133+
# passes it as a proper argv element to openhands.core.main.
134+
# This completely bypasses shell quoting/expansion issues.
133135
mcp_config = self._build_mcp_config_toml()
134136
config_file_path = "~/.openhands/config.toml"
135137

136-
commands = [
137-
"SANDBOX_VOLUMES=${PWD}:/workspace:rw",
138-
"/opt/openhands-venv/bin/python -m openhands.core.main",
139-
f'--task="$(cat {self._TASK_FILE})"',
138+
launcher_lines = [
139+
"import sys, subprocess",
140+
f"task = open('{self._TASK_FILE}').read()",
141+
"cmd = [sys.executable, '-m', 'openhands.core.main', '--task=' + task]",
140142
]
141143
if mcp_config:
142-
commands.append(f"--config-file={config_file_path}")
144+
launcher_lines.append(f"cmd.append('--config-file={config_file_path}')")
145+
launcher_lines.append("sys.exit(subprocess.call(cmd, stdin=subprocess.DEVNULL))")
146+
147+
launcher_script = "; ".join(launcher_lines)
148+
launcher_b64 = base64.b64encode(launcher_script.encode()).decode()
149+
150+
# Write launcher, then execute it — two separate commands to avoid
151+
# any shell interpretation of the task content.
152+
launcher_path = "/tmp/oh_launcher.py"
153+
exec_inputs.append(ExecInput(
154+
command=f"echo '{launcher_b64}' | base64 -d > {launcher_path}",
155+
env=env,
156+
))
143157

144158
main_cmd = (
145-
" ".join(commands)
146-
+ " 2>&1 </dev/null | stdbuf -oL tee /logs/agent/openhands.txt"
159+
f"SANDBOX_VOLUMES=${{PWD}}:/workspace:rw "
160+
f"/opt/openhands-venv/bin/python {launcher_path}"
161+
" 2>&1 | stdbuf -oL tee /logs/agent/openhands.txt"
147162
)
148163

149164
exec_inputs.append(ExecInput(

0 commit comments

Comments
 (0)