fix(inner): never report a blank turn error from ACP-style executors (#4281) - #4362
fix(inner): never report a blank turn error from ACP-style executors (#4281)#4362abhay-codes07 wants to merge 3 commits into
Conversation
…mnigent-ai#4281) Every generic-ACP turn that hit an exception surfaced to the operator as `{"code": "runner_error", "message": "inner executor error: "}` with an empty message. The ACP / Goose / Qwen executors reported failures from their stdout reader via `str(exc)`, which is empty for several stdlib exceptions raised without a message (a bare `RuntimeError()`, `TimeoutError()`, etc.), so the turn failed with no stated reason. Add a shared `describe_exception` helper in `inner/executor.py` that falls back to `repr(exc)` (which always names the exception class) when `str(exc)` is empty, and use it at all three reader error paths (`acp_executor`, `goose_executor`, `qwen_executor`). Also harden the harness adapter so an `ExecutorError` with an empty message from any other path still yields a non-blank "inner executor error" instead of a trailing-blank string. This is the reporting half of omnigent-ai#4281 (the turn error is never blank again); the underlying per-agent failure, previously invisible, now names at least its exception type. Tests: `describe_exception` falls back to repr for a bare exception, preserves a real message verbatim, and is never blank for a range of stdlib exceptions. Signed-off-by: abhay-codes07 <abhaysingh0293@gmail.com>
|
@abhay-codes07 This PR is a Bug fix, Feature, or UI / frontend change but the Demo section is missing or only contains a placeholder. These change types require a screenshot or screen recording so reviewers can see the new behaviour without checking out the branch. Please update the Demo section with:
Use |
…igent-ai#4281) The same blank-message pattern the reader paths had also lives in every executor's `run_turn` failure path: `yield ExecutorError(message=str(exc))` goes blank for a bare exception. The adapter guard added in the previous commit already stops a blank from reaching the operator, but it can only fall back to a generic "no detail" string. Routing these 15 sites through `describe_exception` names the actual exception type instead, across all harnesses (claude-sdk/native, codex, cursor, antigravity, goose, hermes, kimi, kiro, openai-agents, qwen, acp). Mechanical, single-helper change; covered by the `describe_exception` unit tests and the executors' existing run_turn tests. Signed-off-by: abhay-codes07 <abhaysingh0293@gmail.com>
|
Extended the fix in a second commit: the same blank-message pattern lives in every executor's |
|
/review |
|
dhruv0811
left a comment
There was a problem hiding this comment.
LGTM! Thanks for adding the better error handling :)
|
Related issue
Closes #4281
Summary
Every generic-ACP turn that raised an exception surfaced to the operator as
{"code": "runner_error", "message": "inner executor error: "}— an empty message, with the real traceback going only to the harness subprocess logger where an operator can't reach it.Root cause: the ACP / Goose / Qwen executors report a reader failure via
str(exc), which is empty for several stdlib exceptions raised without a message (a bareRuntimeError(),TimeoutError(), …). The harness adapter then re-raisesf"inner executor error: {event.message}"verbatim, so a blankstr(exc)reaches the user as a turn that failed for no stated reason.This fixes the reporting half of the issue (the actionable one the issue calls out):
describe_exception(exc)ininner/executor.py: returnsstr(exc)when non-empty, elserepr(exc)(which always names the exception class). Uses the samestr(exc) or repr(exc)idiom already used elsewhere in the repo.acp_executor.py,goose_executor.py,qwen_executor.py.runtime/harnesses/_executor_adapter.py: anExecutorErrorwith an empty message from any other path now yields a non-blank "inner executor error" rather than a trailing-blank string.The underlying per-agent failure (whatever the exception was) is now at least named by its type instead of being invisible.
Test Plan
Added to
tests/inner/test_acp_executor.py:describe_exceptionfalls back toreprfor a bareRuntimeError()(whosestr()is""), naming the typeruff check+ruff format --checkclean. (Three pre-existing failures in this area — two ACP fake-agent e2e tests and one Goose bwrap sandbox test — reproduce identically on cleanmainin a non-Linux dev env and are unrelated.)Demo
N/A. Backend error-reporting fix, no visual surface. Before: a bare-exception ACP turn fails with
inner executor error:(empty). After: it fails with e.g.inner executor error: RuntimeError(), naming the failure.Type of change
Test coverage
Changelog
Generic-ACP / Goose / Qwen turns that fail now report the exception type instead of a blank "inner executor error: " with no detail.