Skip to content

fix(adapters): report why a turn produced nothing instead of nothing - #664

Merged
Ashin-LX-98 merged 1 commit into
developfrom
fix/adapter-silent-failure-diagnostics
Sep 8, 2026
Merged

fix(adapters): report why a turn produced nothing instead of nothing#664
Ashin-LX-98 merged 1 commit into
developfrom
fix/adapter-silent-failure-diagnostics

Conversation

@Ashin-LX-98

Copy link
Copy Markdown
Collaborator

Follow-up to #663. With the gateway and the credentials both verified, every cell in the matrix now reaches the LLM call and then reports No agent reply within 300s — and nothing else, anywhere. The same key and base URL drive the claude CLI to a correct answer from a shell on the same box, so what is left is that a failing turn has nothing to say for itself. Two reasons, both fixed here.

1. claude.js collected stderr and read it back nowhere

pp.stderrBuf is written on every stderr chunk and appears in exactly no other place in the file. So:

  • Child dies before its first JSON event → no result to quote → the channel gets No response generated. Please try again. and the daemon log gets an exit code. The actual account of what happened is in a string nobody looks at.
  • Child hangs → the watchdog kills it at 300s with Agent process became unresponsive, dropping the buffer again.

codex, gemini and opencode all log their stderr on exit. claude now does too, and additionally uses it on the two paths where it is the only thing there is — the watchdog kill and the silent exit. The "no response" fallback now carries the exit code instead of nothing.

Secrets are stripped on the way out. A CLI failing on auth tends to echo the key it was handed, and this text goes both to the daemon log and to a workspace message. The rule already existed as byte-identical private statics on CodexAdapter and OpenCodeAdapter; a third copy of a security-relevant rule is one too many, so it moves to adapters/utils.js as redactSecrets and both delegate. Redaction runs over the whole buffer before the tail is cut, so a key cannot survive by being split across the boundary — there is a test for that.

2. A dead heat at exactly 300s

adapter its own give-up timer
claude stdout watchdog, 20 × 15s = 300s
codex direct-LLM timeout: 300000 = 300s
opencode TIMEOUT_MS = 300000 = 300s
gemini idle monitor, 20 × 15s = 300s

respond.spec.ts polled for exactly 300s.

So the adapter posts its diagnosis to the channel at the same moment the test stops listening. That is why three rounds of reports have carried the contentless timeout while the real reason was a second away. sendError posts as an ordinary agent chat message, so waiting past the adapters makes that message the assertion's own failure text — the report's note column gets the real error instead of No agent reply within 300s.

Poll raised to 360s, per-test budget to install + 13 min to match.

Testing

  • npm test in agent-connector — 1517 pass, 0 fail (5 new)
  • npm run typecheck + npx vitest run in launcher — clean, 476 pass

Note on when this reaches the nightly

The launcher pins @openagents-org/agent-launcher@0.2.177, so the adapter half of this only affects the matrix after a core release and a launcher bump. The respond.spec.ts half takes effect on the next run.

Not addressed

  • Why the four adapters hang is still open — this makes the next run say so rather than guessing. Worth noting that codex hangs in direct-HTTP mode with no subprocess at all, so whatever it is, it is not only about subprocess IPC.
  • openclaw's openclaw doctor --fix legacy credential migration.
  • gemini's Approval mode overridden … folder is not trusted.

🤖 Generated with Claude Code

Three rounds of the GUI matrix have ended with every agent reaching the
LLM call and then reporting `No agent reply within 300s`, with no other
information anywhere. The gateway and the credentials are both verified
now — the same key and base URL drive the claude CLI to a correct answer
from a shell on the same box — so what is left is that a failing turn has
nothing to say for itself. Two reasons for that, both here.

claude.js collected the child's stderr into `pp.stderrBuf` and read it
back in exactly no place. When the CLI died before emitting its first
JSON event there was no `result` to quote, so the channel got "No
response generated. Please try again." and the daemon log got an exit
code — while the actual account of what happened sat in a string nobody
looked at. When it hung instead, the watchdog killed it at 300s and said
"became unresponsive", again dropping the buffer. codex, gemini and
opencode all log their stderr on exit; claude now does too, and also uses
it on the two paths where it is the only thing there is: the watchdog
kill and the silent exit. The "no response" fallback carries the exit
code rather than nothing.

Secrets are stripped on the way out — a CLI failing on auth tends to echo
the key it was handed. The redaction rule already existed as identical
private statics on codex and opencode; a third copy of a security-
relevant rule is one too many, so it moves to adapters/utils.js and both
delegate. Redaction runs over the whole buffer before the tail is cut,
so a key cannot survive by being split across the boundary.

The other reason is a dead heat. Every adapter gives up at exactly 300s —
claude's stdout watchdog (20 x 15s), codex's direct-LLM request timeout,
opencode's TIMEOUT_MS, gemini's idle monitor — and respond.spec polled
for exactly 300s. The adapter posts its diagnosis to the channel at the
moment the test stops listening, which is why every failure has read as
the contentless timeout while the real reason was a second away. The
spec now waits past it, so the adapter's own message becomes the
assertion's failure text.
@vercel

vercel Bot commented Sep 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
openagents-workspace Ready Ready Preview Sep 8, 2026 8:23am UTC

Request Review

@Ashin-LX-98
Ashin-LX-98 merged commit 417492f into develop Sep 8, 2026
14 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.

1 participant