Skip to content

Fix validate_tool hang: pass stdin=DEVNULL to the validation subprocess#218

Merged
lilly-luo merged 3 commits into
databricks:mainfrom
Edwinhe03:edwin-he/validate-tool-stdin-devnull
Jul 17, 2026
Merged

Fix validate_tool hang: pass stdin=DEVNULL to the validation subprocess#218
lilly-luo merged 3 commits into
databricks:mainfrom
Edwinhe03:edwin-he/validate-tool-stdin-devnull

Conversation

@Edwinhe03

@Edwinhe03 Edwinhe03 commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

What

validate_tool runs each tool's smoke test (pi --print …, codex exec …) via subprocess.run(..., timeout=60) without setting stdin, so the child inherits ucode's stdin. pi and codex open stdin in print/exec mode and block on it. When ucode is launched from a non-interactive parent whose stdin is an open pipe with no EOF (e.g. an agent harness spawning ucode <tool>), validation hangs the full 60s and returns a spurious timed out<tool> validation failed — config reverted, even though the tool is configured correctly.

Fix

Pass stdin=subprocess.DEVNULL — the smoke test is one-shot and never needs input. Benign for every tool.

Verified

Open-stdin-pipe condition, before (main) vs after:

tool before after
pi (real validate_tool) timed out, 60s ok, 0s
codex (real validate_tool) timed out, 60s ok, 0s
real pi --print on sandbox hang, 60s reply, 2s
real codex exec on sandbox hang, 60s reply, 3s

Added TestValidateTool (asserts stdin=DEVNULL; TimeoutExpiredtimed out). Full suite: 875 passed, ruff clean.

`validate_tool` runs each tool's smoke test (e.g. `pi --print "say hi in 5
words or less"`) via `subprocess.run(..., timeout=60)` without setting
`stdin`, so the child inherits ucode's own stdin. In print/headless mode some
agent CLIs (pi among them) still open stdin and block waiting for input/EOF.

When ucode is launched from a non-interactive parent whose stdin is an open
pipe with no EOF — e.g. an agent harness spawning `ucode <tool>` as a
subprocess — the validation command never sees EOF, blocks for the full 60s,
and `validate_tool` returns `(False, "timed out")`. The caller
(`_auto_configure_tool` / configure) then reverts the config and aborts with
"<tool> validation failed — config reverted", even though the tool is
correctly configured and the gateway is reachable.

The validation smoke test is one-shot and never needs interactive input, so
pass `stdin=subprocess.DEVNULL`. This is benign for every tool (an interactive
prompt in a validation run would itself be a bug) and makes validation robust
regardless of how ucode was launched.

Verified on a managed sandbox: `pi --print "say hi"` returns instantly with
`stdin=DEVNULL` but hangs to the timeout when it inherits an open stdin pipe.

Signed-off-by: Edwin He <edwin.he@databricks.com>
@Edwinhe03
Edwinhe03 marked this pull request as draft July 16, 2026 19:32
@Edwinhe03
Edwinhe03 marked this pull request as ready for review July 16, 2026 21:17
@Edwinhe03
Edwinhe03 requested a review from lilly-luo July 16, 2026 21:18
@Edwinhe03
Edwinhe03 marked this pull request as draft July 16, 2026 21:30
Comment thread src/ucode/agents/__init__.py Outdated
lilly-luo
lilly-luo previously approved these changes Jul 17, 2026
Per review: the kwarg is self-explanatory; drop the comment block.
@Edwinhe03
Edwinhe03 marked this pull request as ready for review July 17, 2026 18:38
@Edwinhe03
Edwinhe03 requested a review from lilly-luo July 17, 2026 18:42
@lilly-luo
lilly-luo merged commit a4ec6ec into databricks:main Jul 17, 2026
2 checks passed
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.

2 participants