Skip to content

Fix DinD compose ACP: use Daytona PTY WebSocket for live agent pipes#193

Merged
xdotli merged 1 commit intodev-0.3from
fix/dind-pty-acp
Apr 25, 2026
Merged

Fix DinD compose ACP: use Daytona PTY WebSocket for live agent pipes#193
xdotli merged 1 commit intodev-0.3from
fix/dind-pty-acp

Conversation

@xdotli
Copy link
Copy Markdown
Member

@xdotli xdotli commented Apr 24, 2026

Summary

  • New DaytonaPtyProcess class that uses Daytona SDK's WebSocket PTY API instead of SSH for DinD compose tasks
  • SSH pipes break through the DinD→compose exec chain (Process closed stdout rc=None). WebSocket PTY maintains the connection.
  • Echo-resistant ACP response matching in client.py (filter echoed requests by checking for method field absence)
  • skills_dir: "auto" support in Job for per-task skill resolution (needed after skillsbench PR #720 removed COPY skills from Dockerfiles)

How it works

Old (SSH, breaks):
local → SSH → DinD VM → docker compose exec -T → container → agent
                         ↑ stdout pipe dies here

New (PTY WebSocket):
local → WebSocket → DinD VM PTY → docker compose exec -i -T → container → agent
                    ↑ persistent interactive session
  1. Outer PTY (Daytona WebSocket): keeps connection alive through DinD
  2. Inner -T (compose exec): disables TTY inside container so agent gets clean stdio
  3. Marker-based startup: drains shell output before ACP handshake
  4. Auto-detection: _acp_run.py detects DinD → uses PTY transport automatically

Test results

Task Before After
pedestrian-traffic-counting rc=None, 0 tools reward=0.014, 7 tools
gh-repo-analytics rc=None, 0 tools reward=0.0, 11 tools
pg-essay-to-audiobook rc=None, 0 tools 34 tools (PTY timeout — needs longer readline)

Test plan

  • pedestrian-traffic-counting: agent runs, produces reward
  • gh-repo-analytics: agent runs, 11 tool calls
  • pg-essay-to-audiobook: agent runs 34 tool calls (readline timeout needs increase)
  • Non-compose tasks unaffected (PTY only used for DinD)

Ref: #192


Open in Devin Review

devin-ai-integration[bot]

This comment was marked as resolved.

SSH pipes break through the DinD→compose exec chain, causing
"Process closed stdout (rc=None)" on all compose tasks.

New DaytonaPtyProcess uses Daytona SDK's WebSocket PTY API for the
outer connection (keeps pipe alive), then docker compose exec -i -T
inside (clean stdio for the agent). Includes marker-based startup
to drain shell output before ACP handshake, and echo-resistant
response matching in the ACP client (filter echoed requests by
checking for 'method' field absence).

Also adds skills_dir: "auto" support in Job for per-task skill
resolution after PR #720 removed COPY skills from Dockerfiles.
@xdotli xdotli force-pushed the fix/dind-pty-acp branch from abfb0c2 to aaa6b80 Compare April 25, 2026 01:06
@xdotli xdotli merged commit d813dc2 into dev-0.3 Apr 25, 2026
2 checks passed
@xdotli xdotli deleted the fix/dind-pty-acp branch April 25, 2026 10:04
xdotli added a commit that referenced this pull request Apr 25, 2026
* fix: env-file path mismatch in DinD compose mode

Devin caught a real bug introduced by PR #193 (DinD compose ACP):
src/benchflow/process.py:325 sets remote_env_path = "/tmp/benchflow_env_$$.env"
expecting the remote shell to expand $$ to its PID. But shlex.join() at
line 329 single-quotes the --env-file argument, so docker compose receives
the literal string "/tmp/benchflow_env_$$.env" while the cat heredoc that
writes the file (line 339, raw f-string) does expand $$. The file is
written to /tmp/benchflow_env_<pid>.env and read from /tmp/benchflow_env_$$.env
— silent mismatch, env vars (incl. API keys) silently dropped in DinD
compose tasks.

Fix: use uuid.uuid4().hex[:16] for the unique suffix instead of relying on
shell-side $$ expansion. The path is then a literal that survives quoting.
Apply the same fix to the direct (non-DinD) Daytona branch even though it
was working — uniformity makes the path robust against future quoting
changes.

Also fix a pre-existing SIM103 lint error in _daytona_patches.py that
ruff caught while validating the test changes.

Tests: tests/test_process.py +2 regression tests pinning that no remote
command contains a literal "$$" — would catch this exact regression.
8/8 process tests pass; ruff clean.

* test: reference PR #193 / #198 in regression test docstring

Devin caught: CLAUDE.md mandates regression tests name the commit/PR
they guard. Updated TestDaytonaProcessEnvFilePath docstring to cite
PR #198 (the fix) and PR #193 / commit cdccac7 (the regression).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant