fix: handle codex CLI stderr noise without losing valid stdout

Codex writes diagnostic messages to stderr (e.g. rollout errors) which
cause non-zero exit codes even when valid JSONL output exists on stdout.
Parse stdout first before checking exit code to avoid false errors.
This commit is contained in:
Leandro Barbosa 2026-02-13 14:31:22 -03:00
parent 41e924ec68
commit e44c6d9d7d

View file

@ -50,10 +50,22 @@ func (p *CodexCliProvider) Chat(ctx context.Context, messages []Message, tools [
cmd := exec.CommandContext(ctx, p.command, args...)
cmd.Stdin = bytes.NewReader([]byte(prompt))
var stderr bytes.Buffer
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
stdout, err := cmd.Output()
err := cmd.Run()
// Parse JSONL from stdout even if exit code is non-zero,
// because codex writes diagnostic noise to stderr (e.g. rollout errors)
// but still produces valid JSONL output.
if stdoutStr := stdout.String(); stdoutStr != "" {
resp, parseErr := p.parseJSONLEvents(stdoutStr)
if parseErr == nil && resp != nil && (resp.Content != "" || len(resp.ToolCalls) > 0) {
return resp, nil
}
}
if err != nil {
if ctx.Err() == context.Canceled {
return nil, ctx.Err()
@ -64,7 +76,7 @@ func (p *CodexCliProvider) Chat(ctx context.Context, messages []Message, tools [
return nil, fmt.Errorf("codex cli error: %w", err)
}
return p.parseJSONLEvents(string(stdout))
return p.parseJSONLEvents(stdout.String())
}
// GetDefaultModel returns the default model identifier.