fix(agent-backend): surface parsed CLI exit reasons in cause chains - #1067
Conversation
Operators were seeing a bare `AgentBackendExitError` with no text and no exit code, even when Claude, Codex, or Grok had already parsed a human-readable failure. Inspect copy degraded to "Agent Backend inspection failed (AgentBackendExitError)". This is the diagnostics half of #1056; stderr capture for turns remains #1057. `AgentBackendExitError` now accepts an optional `message` (transitional until #1066). It is sanitized on construction (ANSI stripped, token-shaped secrets redacted, length bounded). Claude `is_error`, Codex `turn.failed`, and Grok stream `error` / max-turns populate it. `runCliCapture` uses captured stdout/stderr. Cause-chain links derive `code` from `exitCode` so the disclosure can render `AgentBackendExitError 1 — <reason>`. Codex inspect failures raise the exit error with probe text instead of wrapping a ConfigError workaround; `formatInspectFailure` already prefers `error.message`. Review follow-up: a parsed stream reason now rides on `runCliTurn` the same way `errorClassification` does, so a CLI that emits JSONL then exits non-zero no longer drops the reason. Tests cover that path with `exit 1` after the error event. Verified with `agent-backend`, Claude, Codex, Grok, `github-service` cause-chain, and install-dependencies fallback specs. Deferred: duplicate sanitizer regexes stay package-local (layering); the nested TypeScript-7 Nx symlink script is a local hook-layout fix, not product behaviour. Closes #1056
Schema classes cannot override the constructor (TS377044). Move message sanitization to AgentBackendExitError.new so agent-backend build and quality-gates typecheck pass. Closes #1056
|
Pushed Change: Verification: Review feedback addressed: none from Automated Review — this addresses the CI typecheck/build failure only. Review feedback declined: none. |
Knip flagged AGENT_BACKEND_EXIT_MESSAGE_MAX as an unused export. Keep the bound private to the sanitizer.
|
Pushed Change: Stop exporting Verification: Review feedback addressed: none from Automated Review — this addresses the CI knip failure only. Review feedback declined: none. |
Operators were seeing a bare
AgentBackendExitErrorwith no text and noexit code, even when Claude, Codex, or Grok had already parsed a
human-readable failure. Inspect copy degraded to "Agent Backend
inspection failed (AgentBackendExitError)". This is the diagnostics
half of #1056; stderr capture for turns remains #1057.
AgentBackendExitErrornow accepts an optionalmessage(transitionaluntil #1066). It is sanitized on construction (ANSI stripped,
token-shaped secrets redacted, length bounded). Claude
is_error,Codex
turn.failed, and Grok streamerror/ max-turns populate it.runCliCaptureuses captured stdout/stderr. Cause-chain links derivecodefromexitCodeso the disclosure can renderAgentBackendExitError 1 — <reason>. Codex inspect failures raise theexit error with probe text instead of wrapping a ConfigError
workaround;
formatInspectFailurealready preferserror.message.Review follow-up: a parsed stream reason now rides on
runCliTurnthesame way
errorClassificationdoes, so a CLI that emits JSONL thenexits non-zero no longer drops the reason. Tests cover that path with
exit 1after the error event.Verified with
agent-backend, Claude, Codex, Grok,github-servicecause-chain, and install-dependencies fallback specs. Deferred:
duplicate sanitizer regexes stay package-local (layering); the nested
TypeScript-7 Nx symlink script is a local hook-layout fix, not product
behaviour.
Closes #1056