fix(skillopt-sleep): also surface codex failures on the tool-call rollout path

Follow-up from a fresh-context review of the prior commit: CodexCliBackend.attempt_with_tools
(the rollout path for tool-requiring tasks) ran codex exec inline, swallowed all exceptions,
and never set last_call_error — so an auth/model/version failure on the tool path still
produced a silent empty->0 with no diagnostic signal, the exact failure class the prior commit
fixed for the _call path. Now it surfaces timeout/exception/non-zero-exit via last_call_error
(response stays empty; never leaks the CLI error text), so a failed tool rollout shows up in
diagnostics.json. Adds a regression test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Daniel Martinez
2026-06-27 23:56:11 -05:00
parent 9fcf5868c3
commit 9fa0716c72
2 changed files with 37 additions and 3 deletions
+14 -3
View File
@@ -890,16 +890,27 @@ class CodexCliBackend(CliBackend):
if self.model:
cmd += ["-m", self.model]
cmd += ["--", prompt]
self.last_call_error = ""
proc = None
try:
subprocess.run(cmd, capture_output=True, text=True, timeout=self.timeout, cwd=work)
except Exception:
pass
proc = subprocess.run(cmd, capture_output=True, text=True, timeout=self.timeout, cwd=work)
except subprocess.TimeoutExpired:
self.last_call_error = f"codex exec (tools) timed out after {self.timeout}s"
except Exception as exc: # noqa: BLE001
self.last_call_error = f"codex exec (tools) failed: {exc}"
resp = ""
try:
with open(out_path, encoding="utf-8") as f:
resp = f.read().strip()
except Exception:
resp = ""
# Surface a failed tool-rollout the SAME way _call does: an auth/model/version
# failure on this path must show up in diagnostics (call_error), not vanish as a
# silent empty->0 scored as a failed rollout. Response stays "" (never the error text).
if not resp and not self.last_call_error and proc is not None and proc.returncode != 0:
self.last_call_error = (
f"codex exec (tools) exited {proc.returncode}: {(proc.stderr or '')[:500]}"
)
self._tokens += len(prompt) // 4 + len(resp) // 4
called: List[str] = []
if os.path.exists(calllog):